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

Public Member Functions

 ClusterMergeAlg (const fhicl::ParameterSet &)
 Constructor. More...
 
 ~ClusterMergeAlg ()
 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 Member Functions

bool linearClusters (reco::ClusterParameters &, reco::ClusterParameters &) const
 
bool mergeClusters (reco::ClusterParameters &, reco::ClusterParameters &) const
 
float closestApproach (const Eigen::Vector3f &, const Eigen::Vector3f &, const Eigen::Vector3f &, const Eigen::Vector3f &, Eigen::Vector3f &, Eigen::Vector3f &, Eigen::Vector3f &) const
 
const reco::ClusterHit3DfindClosestHit3D (const Eigen::Vector3f &, const Eigen::Vector3f &, const reco::HitPairListPtr &) const
 
const reco::ClusterHit3DfindFurthestHit3D (const Eigen::Vector3f &, const Eigen::Vector3f &, const reco::HitPairListPtr &) const
 

Private Attributes

bool fEnableMonitoring
 Data members to follow. More...
 
float fMinTransEigenVal
 Set a mininum allowed value for the transverse eigen values. More...
 
float fMinEigenToProcess
 Don't look anymore at clusters below this size. More...
 
bool fOutputHistograms
 Take the time to create and fill some histograms for diagnostics. More...
 
float fTimeToProcess
 Keep track of how long it took to run this algorithm. More...
 
std::vector< TH1F * > fFirstEigenValueHists
 First Cluster eigen value. More...
 
std::vector< TH1F * > fNextEigenValueHists
 Next Cluster eigen value. More...
 
TH1F * fNumMergedClusters
 How many clusters were merged? More...
 
TH1F * f1stTo2ndPosLenHist
 Distance between cluster centers. More...
 
TH1F * fRMaxFirstHist
 radius of "cylinder" first cluster More...
 
TH1F * fCosMaxFirstHist
 Cos angle beteeen cylinder axis and edge. More...
 
TH1F * fCosFirstAxisHist
 Cos angle between vector between centers and first axis. More...
 
TH1F * f1stTo2ndProjEigenHist
 arc length along vector between centers from first center to cylinder More...
 
TH1F * fRMaxNextHist
 radius of "cylinder" next cluster More...
 
TH1F * fCosMaxNextHist
 Cos angle beteeen cylinder axis and edge. More...
 
TH1F * fCosNextAxisHist
 Cos angle between vector between centers and next axis. More...
 
TH1F * f2ndTo1stProjEigenHist
 arc length along vector between centers from next center to cylinder More...
 
TH1F * fGapBetweenClusHist
 Gap between clusters. More...
 
TH1F * fGapRatToLenHist
 Ratio of gap to distance between centers. More...
 
TH1F * fProjEndPointLenHist
 Projection of vector between the endpoints. More...
 
TH1F * fProjEndPointRatHist
 Ratio of projection to vector length. More...
 
TH1F * fAxesDocaHist
 Closest distance between two primary axes. More...
 
TH1F * f1stDocaArcLRatHist
 arc length to POCA for DOCA first cluster More...
 
TH1F * f2ndDocaArcLRatHist
 arc length to POCA for DOCA second cluster More...
 
TH1F * f1stTo2ndPosLenRatHist
 Ratio of distance between centers and first proj eigen. More...
 
TH1F * fGapRatHist
 Ratio of gap and next proj eigen. More...
 
PrincipalComponentsAlg fPCAAlg
 

Detailed Description

Definition at line 34 of file ClusterMergeAlg_tool.cc.

Constructor & Destructor Documentation

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

Constructor.

Parameters
pset
lar_cluster3d::ClusterMergeAlg::~ClusterMergeAlg ( )

Destructor.

Definition at line 134 of file ClusterMergeAlg_tool.cc.

135 {
136 }

Member Function Documentation

float lar_cluster3d::ClusterMergeAlg::closestApproach ( const Eigen::Vector3f &  P0,
const Eigen::Vector3f &  u0,
const Eigen::Vector3f &  P1,
const Eigen::Vector3f &  u1,
Eigen::Vector3f &  poca0,
Eigen::Vector3f &  poca1,
Eigen::Vector3f &  firstNextUnit 
) const
private

Definition at line 580 of file ClusterMergeAlg_tool.cc.

585 {
586  // Technique is to compute the arclength to each point of closest approach
587  Eigen::Vector3f w0 = P0 - P1;
588  float a(1.);
589  float b(u0.dot(u1));
590  float c(1.);
591  float d(u0.dot(w0));
592  float e(u1.dot(w0));
593  float den(a * c - b * b);
594 
595  // Make sure lines are not colinear
596  if (std::abs(den) > 10. * std::numeric_limits<float>::epsilon())
597  {
598  float arcLen0 = (b * e - c * d) / den;
599  float arcLen1 = (a * e - b * d) / den;
600 
601  poca0 = P0 + arcLen0 * u0;
602  poca1 = P1 + arcLen1 * u1;
603  }
604  // Otherwise, take the poca to be the distance to the line at the second point
605  else
606  {
607  float arcLenToNextPoint = w0.dot(u0);
608 
609  poca0 = P0 + arcLenToNextPoint * u0;
610  poca1 = P1;
611  }
612 
613  firstNextUnit = poca1 - poca0;
614 
615  float docaDist = firstNextUnit.norm();
616 
617  firstNextUnit = firstNextUnit.normalized();
618 
619  return docaDist;
620 }
T abs(T value)
const double e
const double a
static bool * b
Definition: config.cpp:1043
void lar_cluster3d::ClusterMergeAlg::configure ( fhicl::ParameterSet const &  pset)
override

Definition at line 140 of file ClusterMergeAlg_tool.cc.

141 {
142  fEnableMonitoring = pset.get<bool> ("EnableMonitoring", true );
143  fMinTransEigenVal = pset.get<float>("MinTransEigenVal", 0.09 );
144  fMinEigenToProcess = pset.get<float>("MinEigenToProcess", 2.0 );
145  fOutputHistograms = pset.get<bool> ("OutputHistograms", false );
146 
147  fTimeToProcess = 0.;
148 
149  // If asked, define some histograms
150  if (fOutputHistograms)
151  {
152  // Access ART's TFileService, which will handle creating and writing
153  // histograms and n-tuples for us.
155 
156  // Make a directory for these histograms
157  art::TFileDirectory dir = tfs->mkdir("MergeClusters");
158 
159  fFirstEigenValueHists.resize(3,nullptr);
160  fNextEigenValueHists.resize(3,nullptr);
161 
162  std::vector<float> maxValsVec = {20., 50., 250.};
163 
164  for(size_t idx : {0, 1, 2})
165  {
166  fFirstEigenValueHists[idx] = dir.make<TH1F>(Form("FEigen1st%1zu",idx),"Eigen Val", 200, 0., maxValsVec[idx]);
167  fNextEigenValueHists[idx] = dir.make<TH1F>(Form("FEigen2nd%1zu",idx),"Eigen Val", 200, 0., maxValsVec[idx]);
168  }
169 
170  fNumMergedClusters = dir.make<TH1F>("NumMergedClus", "Number Merged", 200, 0., 1000.);
171 
172  f1stTo2ndPosLenHist = dir.make<TH1F>("1stTo2ndPosLen", "Distance between Clusters", 250, 0., 1000.);
173 
174  fRMaxFirstHist = dir.make<TH1F>("rMaxFirst", "Radius of First Cluster", 200, 0., 100.);
175  fCosMaxFirstHist = dir.make<TH1F>("CosMaxFirst", "Cos Angle First Cyl/Axis", 200, 0., 1. );
176  fCosFirstAxisHist = dir.make<TH1F>("CosFirstAxis", "Cos Angle First Next/Axis", 200, 0., 1. );
177  f1stTo2ndProjEigenHist = dir.make<TH1F>("1stTo2ndProjEigen", "Projected Distance First", 200, 0., 200.);
178 
179  fRMaxNextHist = dir.make<TH1F>("rMaxNext", "Radius of Next Cluster", 200, 0., 100.);
180  fCosMaxNextHist = dir.make<TH1F>("CosMaxNext", "Cos Angle Next Cyl/Axis", 200, 0., 1. );
181  fCosNextAxisHist = dir.make<TH1F>("CosNextAxis", "Cos Angle Next Next/Axis", 200, 0., 1. );
182  f2ndTo1stProjEigenHist = dir.make<TH1F>("2ndTo1stProjEigen", "Projected Distance Next", 200, 0., 200.);
183 
184  fGapBetweenClusHist = dir.make<TH1F>("ClusterGap", "Gap Between Clusters", 400, -200., 200.);
185  fGapRatToLenHist = dir.make<TH1F>("GapRatToLen", "Ratio Gap to Distance", 100, -8., 2.);
186  fProjEndPointLenHist = dir.make<TH1F>("ProjEndPointLen", "Projected End Point Len", 200, -100., 100.);
187  fProjEndPointRatHist = dir.make<TH1F>("ProjEndPointRat", "Projected End Point Ratio", 100, 0., 1.);
188 
189  fAxesDocaHist = dir.make<TH1F>("AxesDocaHist", "DOCA", 200, 0., 25.);
190  f1stDocaArcLRatHist = dir.make<TH1F>("ALenPOCA1Hist", "Arc Len to POCA 1", 400, -50., 50.);
191  f2ndDocaArcLRatHist = dir.make<TH1F>("ALenPOCA2Hist", "Arc Len to POCA 2", 400, -50., 50.);
192 
193  f1stTo2ndPosLenRatHist = dir.make<TH1F>("1stTo2ndPosLenRat", "Ratio clus dist to eigen", 200., 0., 20.);
194  fGapRatHist = dir.make<TH1F>("GapRat", "Ratio Gap to Next Eigen", 400, -20., 20.);
195  }
196 
197  return;
198 }
std::vector< TH1F * > fNextEigenValueHists
Next Cluster eigen value.
std::vector< TH1F * > fFirstEigenValueHists
First Cluster eigen value.
TH1F * fCosMaxFirstHist
Cos angle beteeen cylinder axis and edge.
float fTimeToProcess
Keep track of how long it took to run this algorithm.
TH1F * f2ndDocaArcLRatHist
arc length to POCA for DOCA second cluster
bool fOutputHistograms
Take the time to create and fill some histograms for diagnostics.
string dir
TH1F * fRMaxFirstHist
radius of "cylinder" first cluster
TH1F * fGapRatHist
Ratio of gap and next proj eigen.
TH1F * fCosFirstAxisHist
Cos angle between vector between centers and first axis.
TH1F * fProjEndPointRatHist
Ratio of projection to vector length.
float fMinEigenToProcess
Don&#39;t look anymore at clusters below this size.
TH1F * fCosNextAxisHist
Cos angle between vector between centers and next axis.
TH1F * f2ndTo1stProjEigenHist
arc length along vector between centers from next center to cylinder
TH1F * f1stTo2ndPosLenRatHist
Ratio of distance between centers and first proj eigen.
TH1F * fRMaxNextHist
radius of "cylinder" next cluster
bool fEnableMonitoring
Data members to follow.
TH1F * f1stTo2ndProjEigenHist
arc length along vector between centers from first center to cylinder
TH1F * fNumMergedClusters
How many clusters were merged?
TH1F * fProjEndPointLenHist
Projection of vector between the endpoints.
float fMinTransEigenVal
Set a mininum allowed value for the transverse eigen values.
TH1F * fAxesDocaHist
Closest distance between two primary axes.
TH1F * fGapRatToLenHist
Ratio of gap to distance between centers.
TH1F * fCosMaxNextHist
Cos angle beteeen cylinder axis and edge.
TH1F * fGapBetweenClusHist
Gap between clusters.
TH1F * f1stDocaArcLRatHist
arc length to POCA for DOCA first cluster
TH1F * f1stTo2ndPosLenHist
Distance between cluster centers.
const reco::ClusterHit3D * lar_cluster3d::ClusterMergeAlg::findClosestHit3D ( const Eigen::Vector3f &  refPoint,
const Eigen::Vector3f &  refVector,
const reco::HitPairListPtr hitList 
) const
private

Definition at line 622 of file ClusterMergeAlg_tool.cc.

623 {
624  const reco::ClusterHit3D* nearestHit3D(hitList.front());
625  float closest(std::numeric_limits<float>::max());
626 
627  for(const auto& hit3D : hitList)
628  {
629  Eigen::Vector3f refToHitVec = hit3D->getPosition() - refPoint;
630  float arcLenToHit = refToHitVec.dot(refVector);
631 
632  if (arcLenToHit < closest)
633  {
634  nearestHit3D = hit3D;
635  closest = arcLenToHit;
636  }
637  }
638 
639  return nearestHit3D;
640 }
static int max(int a, int b)
const reco::ClusterHit3D * lar_cluster3d::ClusterMergeAlg::findFurthestHit3D ( const Eigen::Vector3f &  refPoint,
const Eigen::Vector3f &  refVector,
const reco::HitPairListPtr hitList 
) const
private

Definition at line 642 of file ClusterMergeAlg_tool.cc.

643 {
644  const reco::ClusterHit3D* nearestHit3D(hitList.front());
645  float furthest(-std::numeric_limits<float>::max());
646 
647  for(const auto& hit3D : hitList)
648  {
649  Eigen::Vector3f refToHitVec = hit3D->getPosition() - refPoint;
650  float arcLenToHit = refToHitVec.dot(refVector);
651 
652  if (arcLenToHit > furthest)
653  {
654  nearestHit3D = hit3D;
655  furthest = arcLenToHit;
656  }
657  }
658 
659  return nearestHit3D;
660 }
static int max(int a, int b)
float lar_cluster3d::ClusterMergeAlg::getTimeToExecute ( ) const
inlineoverridevirtual

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

Implements lar_cluster3d::IClusterModAlg.

Definition at line 70 of file ClusterMergeAlg_tool.cc.

70 {return fTimeToProcess;}
float fTimeToProcess
Keep track of how long it took to run this algorithm.
void lar_cluster3d::ClusterMergeAlg::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 200 of file ClusterMergeAlg_tool.cc.

201 {
202  return;
203 }
bool lar_cluster3d::ClusterMergeAlg::linearClusters ( reco::ClusterParameters firstCluster,
reco::ClusterParameters nextCluster 
) const
private

Definition at line 324 of file ClusterMergeAlg_tool.cc.

325 {
326  // Assume failure
327  bool consistent(false);
328 
329  // The goal here is to compare the two input PCA's and determine if they are effectively colinear and
330  // within reasonable range to consider merging them. Note that a key assumption is that the first input
331  // PCA is from the "bigger" cluster, the second is "smaller" and may have a less reliable PCA.
332 
333  // Dereference the PCA's
334  const reco::PrincipalComponents& firstPCA = firstCluster.getFullPCA();
335  const reco::PrincipalComponents& nextPCA = nextCluster.getFullPCA();
336 
337  // Recover the positions of the centers of the two clusters
338  const Eigen::Vector3f& firstCenter = firstPCA.getAvePosition();
339  const Eigen::Vector3f& nextCenter = nextPCA.getAvePosition();
340 
341  // And form a vector between the two centers
342  Eigen::Vector3f firstPosToNextPosVec = nextCenter - firstCenter;
343  Eigen::Vector3f firstPosToNextPosUnit = firstPosToNextPosVec.normalized();
344  float firstPosToNextPosLen = firstPosToNextPosVec.norm();
345 
346  // Now get the first PCA's primary axis and since we'll use them get all of them at once...
347  Eigen::Vector3f firstAxis0(firstPCA.getEigenVectors().row(0));
348  Eigen::Vector3f firstAxis1(firstPCA.getEigenVectors().row(1));
349  Eigen::Vector3f firstAxis2(firstPCA.getEigenVectors().row(2));
350 
351  // Will want the distance of closest approach of the next cluser's center to the primary, start by finding arc length
352  float arcLenToNextDoca = firstPosToNextPosVec.dot(firstAxis2);
353 
354  // Adopt the convention that the cluster axis is in same direction as vector from first to next centers
355  // And preserve the overall orientation of the PCA by flipping all if we flip the first one
356  if (arcLenToNextDoca < 0.)
357  {
358  firstAxis0 = -firstAxis0;
359  firstAxis1 = -firstAxis1;
360  firstAxis2 = -firstAxis2;
361  arcLenToNextDoca = -arcLenToNextDoca;
362  }
363 
364  // Recover the eigen values of the first and second PCAs for selection cuts
365  Eigen::Vector3f firstEigenVals(std::min(1.5 * sqrt(std::max(firstPCA.getEigenValues()[0],fMinTransEigenVal)), 20.),
366  std::min(1.5 * sqrt(std::max(firstPCA.getEigenValues()[1],fMinTransEigenVal)), 50.),
367  std::min(1.5 * sqrt( firstPCA.getEigenValues()[2]), 250.));
368 
369  // We treat the PCA as defining an elliptical tube and we use the projection of the vector between centers to
370  // get the radius to the edge of the tube, from which we can determine the projected length inside the tube
371  Eigen::Vector2f firstProj01Unit = Eigen::Vector2f(firstPosToNextPosUnit.dot(firstAxis0),firstPosToNextPosUnit.dot(firstAxis1)).normalized();
372  float firstEigen0Proj = firstEigenVals[0] * firstProj01Unit[0];
373  float firstEigen1Proj = firstEigenVals[1] * firstProj01Unit[1];
374  float rMaxFirst = std::sqrt(firstEigen0Proj * firstEigen0Proj + firstEigen1Proj * firstEigen1Proj);
375  float cosMaxFirst = firstEigenVals[2] / std::sqrt(firstEigenVals[2] * firstEigenVals[2] + rMaxFirst * rMaxFirst);
376  float cosFirstAxis = firstAxis2.dot(firstPosToNextPosUnit);
377 
378  // Now calculate a measure of the length inside the tube along the vector between the cluster centers
379  float firstEigenVal2 = firstEigenVals[2];
380  float firstToNextProjEigen = firstEigenVal2;
381 
382  // There are two cases to consider, the first is that the vector exits out the side of the tube
383  if (cosFirstAxis < cosMaxFirst)
384  {
385  // In this case we need the sign of the angle between the vector and the cluster primary axis
386  float sinFirstAxis = std::sqrt(1. - cosFirstAxis * cosFirstAxis);
387 
388  // Here the length will be given by the radius, not the primary eigen value
389  firstToNextProjEigen = rMaxFirst / sinFirstAxis;
390  }
391  else firstToNextProjEigen /= cosFirstAxis;
392 
393  // Get scale factor for selecting this pair
394  float firstPosToNextPosScaleFactor = 8.;
395 
396  // A brief interlude to fill a few histograms
397  if (fOutputHistograms)
398  {
399  f1stTo2ndPosLenHist->Fill(firstPosToNextPosLen, 1.);
400  fRMaxFirstHist->Fill(rMaxFirst, 1.);
401  fCosMaxFirstHist->Fill(cosMaxFirst, 1.);
402  fCosFirstAxisHist->Fill(cosFirstAxis, 1.);
403  f1stTo2ndProjEigenHist->Fill(firstToNextProjEigen, 1.);
404  }
405 
406  // This makes first selection, it should eliminate most of the junk cases:
407  if (firstPosToNextPosLen < firstPosToNextPosScaleFactor * firstToNextProjEigen)
408  {
409  // Recover the axes for the next PCA and make sure pointing convention is observed
410  Eigen::Vector3f nextAxis0(nextPCA.getEigenVectors().row(0));
411  Eigen::Vector3f nextAxis1(nextPCA.getEigenVectors().row(1));
412  Eigen::Vector3f nextAxis2(nextPCA.getEigenVectors().row(2));
413 
414  // Recover the cos of the angle between the primary axes...
415  float cosFirstNextAxis = firstAxis2.dot(nextAxis2);
416 
417  // And in this case we want to choose the sign of the next cluster's axes so that the
418  // primary axes "point" in the same direction
419  if (cosFirstNextAxis < 0.)
420  {
421  nextAxis0 = -nextAxis0;
422  nextAxis1 = -nextAxis1;
423  nextAxis2 = -nextAxis2;
424  cosFirstNextAxis = -cosFirstNextAxis;
425  }
426 
427  // Get the eigen values again
428  Eigen::Vector3f nextEigenVals(std::min(1.5 * sqrt(std::max(nextPCA.getEigenValues()[0],fMinTransEigenVal)), 20.),
429  std::min(1.5 * sqrt(std::max(nextPCA.getEigenValues()[1],fMinTransEigenVal)), 50.),
430  std::min(1.5 * sqrt( nextPCA.getEigenValues()[2]), 250.));
431 
432  // Repeat the calculation of the length of the vector through the cluster "tube"...
433  Eigen::Vector2f nextProj01Unit = Eigen::Vector2f(firstPosToNextPosUnit.dot(nextAxis0),firstPosToNextPosUnit.dot(nextAxis1)).normalized();
434  float nextEigen0Proj = nextEigenVals[0] * nextProj01Unit[0];
435  float nextEigen1Proj = nextEigenVals[1] * nextProj01Unit[1];
436  float rMaxNext = std::sqrt(nextEigen0Proj * nextEigen0Proj + nextEigen1Proj * nextEigen1Proj);
437  float cosMaxNext = nextEigenVals[2] / std::sqrt(nextEigenVals[2] * nextEigenVals[2] + rMaxNext * rMaxNext);
438  float cosNextAxis = std::abs(nextAxis2.dot(firstPosToNextPosUnit));
439 
440  // Now calculate a measure of the length inside the cylider along the vector between the cluster centers
441  float nextToFirstProjEigen = nextEigenVals[2];
442 
443  // There are two cases to consider, the first is that the vector exits out the side of the cylinder
444  if (cosNextAxis < cosMaxNext)
445  {
446  // In this case we need the sign of the angle between the vector and the cluster primary axis
447  float sinNextAxis = std::sqrt(1. - cosNextAxis * cosNextAxis);
448 
449  // Here the length will be given by the radius, not the primary eigen value
450  nextToFirstProjEigen = rMaxNext / sinNextAxis;
451  }
452  else nextToFirstProjEigen /= cosNextAxis;
453 
454  // Allow a generous gap but significantly derate as angle to next cluster increases
455  //float nextToFirstScaleFactor = 6. * cosFirstNextAxis;
456  float nextToFirstScaleFactor = 8. * cosFirstNextAxis;
457 
458  // Form the "gap" along the axis between centers from the projections of the eigen values
459  // Note the gap can be negative
460  float gapFirstToNext = firstPosToNextPosLen - firstToNextProjEigen - nextToFirstProjEigen;
461 
462  // Look at the presumed nearest endpoints of the two clusters
463  Eigen::Vector3f firstEndPoint = firstCenter + firstEigenVals[2] * firstAxis2;
464  Eigen::Vector3f nextTailPoint = nextCenter - nextEigenVals[2] * nextAxis2;
465  Eigen::Vector3f endToTailVec = nextTailPoint - firstEndPoint;
466 
467  // Get projection along vector between centers
468  float endPointProjection = endToTailVec.dot(firstPosToNextPosUnit);
469  float endToTailLen = endToTailVec.norm();
470 
471  // Another brief interlude to fill some histograms
472  if (fOutputHistograms)
473  {
474  for(size_t idx = 0; idx < 3; idx++) fNextEigenValueHists[idx]->Fill(nextEigenVals[idx],1.);
475 
476  fRMaxNextHist->Fill(rMaxNext, 1.);
477  fCosMaxNextHist->Fill(cosMaxNext, 1.);
478  fCosNextAxisHist->Fill(cosNextAxis, 1.);
479  f2ndTo1stProjEigenHist->Fill(nextToFirstProjEigen, 1.);
480  fGapBetweenClusHist->Fill(gapFirstToNext, 1.);
481  fProjEndPointLenHist->Fill(endPointProjection, 1.);
482  fProjEndPointRatHist->Fill(std::abs(endPointProjection)/endToTailLen, 1.);
483  }
484 
485  // We mirror here the first selection above but now operate on the distance between centers less
486  // the first cluster's projected eigen value
487  if (gapFirstToNext < nextToFirstScaleFactor * nextToFirstProjEigen || (std::abs(endPointProjection) < nextToFirstProjEigen && endToTailLen < nextEigenVals[2]))
488  {
489  // Now check the distance of closest approach betweent the two vectors
490  // Closest approach calculaiton results vectors
491  Eigen::Vector3f firstPoca;
492  Eigen::Vector3f nextPoca;
493  Eigen::Vector3f firstToNextUnit;
494 
495  // Recover the doca of the two axes and their points of closest approach along each axis
496  float lineDoca = closestApproach(firstCenter, firstAxis2, nextCenter, nextAxis2, firstPoca, nextPoca, firstToNextUnit);
497 
498  // Get the range through the first clusters "tube" for this doca vec
499  Eigen::Vector3f firstPOCAProjUnit = Eigen::Vector3f(firstToNextUnit.dot(firstAxis0),firstToNextUnit.dot(firstAxis1),firstToNextUnit.dot(firstAxis1)).normalized();
500  float firstPOCAVecProjEigen = std::sqrt(std::pow(firstEigenVals[0] * firstPOCAProjUnit[0],2)
501  + std::pow(firstEigenVals[1] * firstPOCAProjUnit[1],2)
502  + std::pow(firstEigenVals[2] * firstPOCAProjUnit[2],2));
503 
504  // Similarly for the next vector
505  Eigen::Vector3f nextPOCAProjUnit = Eigen::Vector3f(firstToNextUnit.dot(firstAxis0),firstToNextUnit.dot(firstAxis1),firstToNextUnit.dot(firstAxis1)).normalized();
506  float nextPOCAVecProjEigen = std::sqrt(std::pow(nextEigenVals[0] * nextPOCAProjUnit[0],2)
507  + std::pow(nextEigenVals[1] * nextPOCAProjUnit[1],2)
508  + std::pow(nextEigenVals[2] * nextPOCAProjUnit[2],2));
509 
510  if (fOutputHistograms)
511  {
512  // The below returned the signed arc lengths to their respective pocas
513  float arcLenToFirstPoca = (firstPoca - firstCenter).dot(firstAxis2);
514  float arcLenToNextPoca = (nextPoca - nextCenter ).dot(nextAxis2);
515 
516  fAxesDocaHist->Fill(lineDoca, 1.);
517  f1stDocaArcLRatHist->Fill(arcLenToFirstPoca/firstEigenVals[2],1.);
518  f2ndDocaArcLRatHist->Fill(arcLenToNextPoca/nextEigenVals[2],1.);
519  }
520 
521  // Scaling factor to increase doca distance as distance grows
522  float rMaxScaleFactor = 1.2;
523 
524  if (lineDoca < rMaxScaleFactor * (firstPOCAVecProjEigen + nextPOCAVecProjEigen))
525  {
526  consistent = true;
527 
528  if (fOutputHistograms)
529  {
530  f1stTo2ndPosLenRatHist->Fill(firstPosToNextPosLen/firstToNextProjEigen, 1.);
531  }
532  }
533  }
534  }
535 
536  return consistent;
537 }
std::vector< TH1F * > fNextEigenValueHists
Next Cluster eigen value.
float closestApproach(const Eigen::Vector3f &, const Eigen::Vector3f &, const Eigen::Vector3f &, const Eigen::Vector3f &, Eigen::Vector3f &, Eigen::Vector3f &, Eigen::Vector3f &) const
TH1F * fCosMaxFirstHist
Cos angle beteeen cylinder axis and edge.
constexpr T pow(T x)
Definition: pow.h:72
TH1F * f2ndDocaArcLRatHist
arc length to POCA for DOCA second cluster
bool fOutputHistograms
Take the time to create and fill some histograms for diagnostics.
TH1F * fRMaxFirstHist
radius of "cylinder" first cluster
TH1F * fCosFirstAxisHist
Cos angle between vector between centers and first axis.
TH1F * fProjEndPointRatHist
Ratio of projection to vector length.
T abs(T value)
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:246
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:477
TH1F * fCosNextAxisHist
Cos angle between vector between centers and next axis.
TH1F * f2ndTo1stProjEigenHist
arc length along vector between centers from next center to cylinder
TH1F * f1stTo2ndPosLenRatHist
Ratio of distance between centers and first proj eigen.
const Eigen::Vector3f & getAvePosition() const
Definition: Cluster3D.h:248
TH1F * fRMaxNextHist
radius of "cylinder" next cluster
TH1F * f1stTo2ndProjEigenHist
arc length along vector between centers from first center to cylinder
static int max(int a, int b)
TH1F * fProjEndPointLenHist
Projection of vector between the endpoints.
float fMinTransEigenVal
Set a mininum allowed value for the transverse eigen values.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
TH1F * fAxesDocaHist
Closest distance between two primary axes.
TH1F * fCosMaxNextHist
Cos angle beteeen cylinder axis and edge.
TH1F * fGapBetweenClusHist
Gap between clusters.
TH1F * f1stDocaArcLRatHist
arc length to POCA for DOCA first cluster
TH1F * f1stTo2ndPosLenHist
Distance between cluster centers.
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
bool lar_cluster3d::ClusterMergeAlg::mergeClusters ( reco::ClusterParameters firstClusterParams,
reco::ClusterParameters nextClusterParams 
) const
private

Definition at line 539 of file ClusterMergeAlg_tool.cc.

540 {
541  bool merged(false);
542 
543  // Merge the next cluster into the first one
544  // Get the hits
545  reco::HitPairListPtr& hitPairListPtr = firstClusterParams.getHitPairListPtr();
546 
547  // We copy the hits from the old to new but note that we need to update the parameters for each 2D hit we add
548  for(const auto* hit : nextClusterParams.getHitPairListPtr())
549  {
550  hitPairListPtr.push_back(hit);
551 
552  for(const auto* hit2D : hit->getHits())
553  if (hit2D) firstClusterParams.UpdateParameters(hit2D);
554  }
555 
556  // Recalculate the PCA
557  fPCAAlg.PCAAnalysis_3D(firstClusterParams.getHitPairListPtr(), firstClusterParams.getFullPCA());
558 
559  // Must have a valid pca
560  if (firstClusterParams.getFullPCA().getSvdOK())
561  {
562  // Finish out the merging here
563  reco::Hit3DToEdgeMap& firstEdgeMap = firstClusterParams.getHit3DToEdgeMap();
564  reco::Hit3DToEdgeMap& nextEdgeMap = nextClusterParams.getHit3DToEdgeMap();
565 
566  for(const auto& pair : nextEdgeMap) firstEdgeMap[pair.first] = pair.second;
567 
568  // Set the skeleton PCA to make sure it has some value
569  firstClusterParams.getSkeletonPCA() = firstClusterParams.getFullPCA();
570 
571  // Zap the cluster we merged into the new one...
572  nextClusterParams = reco::ClusterParameters();
573 
574  merged = true;
575  }
576 
577  return merged;
578 }
bool getSvdOK() const
Definition: Cluster3D.h:244
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
reco::PrincipalComponents & getSkeletonPCA()
Definition: Cluster3D.h:478
reco::Hit3DToEdgeMap & getHit3DToEdgeMap()
Definition: Cluster3D.h:479
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:476
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:477
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:335
void UpdateParameters(const reco::ClusterHit2D *hit)
Definition: Cluster3D.h:452
Detector simulation of raw signals on wires.
std::unordered_map< const reco::ClusterHit3D *, reco::EdgeList > Hit3DToEdgeMap
Definition: Cluster3D.h:347
void lar_cluster3d::ClusterMergeAlg::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 205 of file ClusterMergeAlg_tool.cc.

206 {
207  /**
208  * @brief Top level interface for algorithm to consider pairs of clusters from the input
209  * list and determine if they are consistent with each other and, therefore, should
210  * be merged. This is done by looking at the PCA for each cluster and looking at the
211  * projection of the primary axis along the vector connecting their centers.
212  */
213 
214  // Initial clustering is done, now trim the list and get output parameters
215  cet::cpu_timer theClockBuildClusters;
216 
217  // Start clocks if requested
218  if (fEnableMonitoring) theClockBuildClusters.start();
219 
220  // Resort by the largest first eigen value (so the "longest" cluster)
221  clusterParametersList.sort([](auto& left, auto& right){return left.getFullPCA().getEigenValues()[2] > right.getFullPCA().getEigenValues()[2];});
222 
223  // The idea is to continually loop through all clusters until we get to the point where we are no longer doing any merging.
224  // If two clusters are merged then we need to recycle through again because it may be that the new cluster can match when
225  // it might not have in the past
226  size_t lastClusterListCount = clusterParametersList.size() + 1;
227  reco::ClusterParametersList::iterator lastFirstClusterItr = clusterParametersList.begin();
228 
229  int numMergedClusters(0);
230  int nOutsideLoops(0);
231 
232  while(clusterParametersList.size() != lastClusterListCount)
233  {
234  // Update the last count
235  lastClusterListCount = clusterParametersList.size();
236 
237  // Keep track of the first cluster iterator each pass through
238  reco::ClusterParametersList::iterator firstClusterItr = lastFirstClusterItr++;
239 
240  // Loop through the clusters
241  while(firstClusterItr != clusterParametersList.end())
242  {
243  reco::ClusterParameters& firstClusterParams = *firstClusterItr;
244  reco::ClusterParametersList::iterator nextClusterItr = firstClusterItr;
245 
246  // Take a brief interlude to do some histogramming
247  if (fOutputHistograms)
248  {
249  const reco::PrincipalComponents& firstPCA = firstClusterParams.getFullPCA();
250 
251  Eigen::Vector3f firstEigenVals(std::min(1.5 * std::sqrt(std::max(firstPCA.getEigenValues()[0],fMinTransEigenVal)), 50.),
252  std::min(1.5 * std::sqrt(std::max(firstPCA.getEigenValues()[1],fMinTransEigenVal)), 100.),
253  1.5 * std::sqrt( firstPCA.getEigenValues()[2]));
254 
255  for(size_t idx = 0; idx < 3; idx++) fFirstEigenValueHists[idx]->Fill(firstEigenVals[idx],1.);
256  }
257 
258  // Once you get down to the smallest clusters if they haven't already been absorbed there is no need to check them
259  if (firstClusterParams.getFullPCA().getEigenValues()[2] < fMinEigenToProcess) break;
260 
261  while(++nextClusterItr != clusterParametersList.end())
262  {
263  reco::ClusterParameters& nextClusterParams = *nextClusterItr;
264 
265  // On any given loop through here it **might** be that the first cluster has been modified. So can't cache
266  // the parameters, need the curret ones
267  if (linearClusters(firstClusterParams,nextClusterParams))
268  {
269  if (mergeClusters(firstClusterParams, nextClusterParams))
270  {
271  // Now remove the "next" cluster
272  nextClusterItr = clusterParametersList.erase(nextClusterItr);
273 
274  // Our new cluster may be larger than those before it so we should try to move backwards to make sure to
275  // give now smaller clusters the chance to get merged as well
276  reco::ClusterParametersList::iterator biggestItr = firstClusterItr;
277 
278  // Step backwards until we hit the beginning of the list
279  while(biggestItr-- != clusterParametersList.begin())
280  {
281  // The list has already been sorted largest to smallest so if we find a cluster that is "larger" then
282  // we have hit the limit
283  if ((*biggestItr).getFullPCA().getEigenValues()[2] > (*firstClusterItr).getFullPCA().getEigenValues()[2])
284  {
285  // Want to insert after the cluster with the larger primary axes.. but there is
286  // no point in doing anything if the new cluster is already in the right spot
287  if (++biggestItr != firstClusterItr) clusterParametersList.splice(biggestItr, clusterParametersList, firstClusterItr);
288 
289  break;
290  }
291  }
292 
293  // Restart loop?
294  nextClusterItr = firstClusterItr;
295 
296  numMergedClusters++;
297  }
298  }
299  }
300 
301  firstClusterItr++;
302  }
303 
304  nOutsideLoops++;
305  }
306 
307  std::cout << "==> # merged: " << numMergedClusters << ", in " << nOutsideLoops << " outside loops " << std::endl;
308 
309  if (fOutputHistograms) fNumMergedClusters->Fill(numMergedClusters, 1.);
310 
311 
312  if (fEnableMonitoring)
313  {
314  theClockBuildClusters.stop();
315 
316  fTimeToProcess = theClockBuildClusters.accumulated_real_time();
317  }
318 
319  mf::LogDebug("Cluster3D") << ">>>>> Merge clusters done, found " << clusterParametersList.size() << " clusters" << std::endl;
320 
321  return;
322 }
intermediate_table::iterator iterator
std::vector< TH1F * > fFirstEigenValueHists
First Cluster eigen value.
float fTimeToProcess
Keep track of how long it took to run this algorithm.
bool fOutputHistograms
Take the time to create and fill some histograms for diagnostics.
float fMinEigenToProcess
Don&#39;t look anymore at clusters below this size.
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:246
bool mergeClusters(reco::ClusterParameters &, reco::ClusterParameters &) const
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:477
bool fEnableMonitoring
Data members to follow.
static int max(int a, int b)
TH1F * fNumMergedClusters
How many clusters were merged?
bool linearClusters(reco::ClusterParameters &, reco::ClusterParameters &) const
float fMinTransEigenVal
Set a mininum allowed value for the transverse eigen values.
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
double accumulated_real_time() const
Definition: cpu_timer.cc:66
void start()
Definition: cpu_timer.cc:83
QTextStream & endl(QTextStream &s)

Member Data Documentation

TH1F* lar_cluster3d::ClusterMergeAlg::f1stDocaArcLRatHist
private

arc length to POCA for DOCA first cluster

Definition at line 117 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::f1stTo2ndPosLenHist
private

Distance between cluster centers.

Definition at line 99 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::f1stTo2ndPosLenRatHist
private

Ratio of distance between centers and first proj eigen.

Definition at line 120 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::f1stTo2ndProjEigenHist
private

arc length along vector between centers from first center to cylinder

Definition at line 104 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::f2ndDocaArcLRatHist
private

arc length to POCA for DOCA second cluster

Definition at line 118 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::f2ndTo1stProjEigenHist
private

arc length along vector between centers from next center to cylinder

Definition at line 109 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fAxesDocaHist
private

Closest distance between two primary axes.

Definition at line 116 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fCosFirstAxisHist
private

Cos angle between vector between centers and first axis.

Definition at line 103 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fCosMaxFirstHist
private

Cos angle beteeen cylinder axis and edge.

Definition at line 102 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fCosMaxNextHist
private

Cos angle beteeen cylinder axis and edge.

Definition at line 107 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fCosNextAxisHist
private

Cos angle between vector between centers and next axis.

Definition at line 108 of file ClusterMergeAlg_tool.cc.

bool lar_cluster3d::ClusterMergeAlg::fEnableMonitoring
private

Data members to follow.

If true then turn on monitoring (e.g. timing)

Definition at line 87 of file ClusterMergeAlg_tool.cc.

std::vector<TH1F*> lar_cluster3d::ClusterMergeAlg::fFirstEigenValueHists
private

First Cluster eigen value.

Definition at line 95 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fGapBetweenClusHist
private

Gap between clusters.

Definition at line 111 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fGapRatHist
private

Ratio of gap and next proj eigen.

Definition at line 121 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fGapRatToLenHist
private

Ratio of gap to distance between centers.

Definition at line 112 of file ClusterMergeAlg_tool.cc.

float lar_cluster3d::ClusterMergeAlg::fMinEigenToProcess
private

Don't look anymore at clusters below this size.

Definition at line 89 of file ClusterMergeAlg_tool.cc.

float lar_cluster3d::ClusterMergeAlg::fMinTransEigenVal
private

Set a mininum allowed value for the transverse eigen values.

Definition at line 88 of file ClusterMergeAlg_tool.cc.

std::vector<TH1F*> lar_cluster3d::ClusterMergeAlg::fNextEigenValueHists
private

Next Cluster eigen value.

Definition at line 96 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fNumMergedClusters
private

How many clusters were merged?

Definition at line 97 of file ClusterMergeAlg_tool.cc.

bool lar_cluster3d::ClusterMergeAlg::fOutputHistograms
private

Take the time to create and fill some histograms for diagnostics.

Definition at line 90 of file ClusterMergeAlg_tool.cc.

PrincipalComponentsAlg lar_cluster3d::ClusterMergeAlg::fPCAAlg
private

Definition at line 123 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fProjEndPointLenHist
private

Projection of vector between the endpoints.

Definition at line 113 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fProjEndPointRatHist
private

Ratio of projection to vector length.

Definition at line 114 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fRMaxFirstHist
private

radius of "cylinder" first cluster

Definition at line 101 of file ClusterMergeAlg_tool.cc.

TH1F* lar_cluster3d::ClusterMergeAlg::fRMaxNextHist
private

radius of "cylinder" next cluster

Definition at line 106 of file ClusterMergeAlg_tool.cc.

float lar_cluster3d::ClusterMergeAlg::fTimeToProcess
mutableprivate

Keep track of how long it took to run this algorithm.

Definition at line 93 of file ClusterMergeAlg_tool.cc.


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