LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
lar_cluster3d::ClusterMergeAlg Class Referenceabstract
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...
 
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 143 of file ClusterMergeAlg_tool.cc.

143 {}

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 606 of file ClusterMergeAlg_tool.cc.

References util::abs(), d, den, and e.

Referenced by getTimeToExecute(), and linearClusters().

613  {
614  // Technique is to compute the arclength to each point of closest approach
615  Eigen::Vector3f w0 = P0 - P1;
616  float a(1.);
617  float b(u0.dot(u1));
618  float c(1.);
619  float d(u0.dot(w0));
620  float e(u1.dot(w0));
621  float den(a * c - b * b);
622 
623  // Make sure lines are not colinear
624  if (std::abs(den) > 10. * std::numeric_limits<float>::epsilon()) {
625  float arcLen0 = (b * e - c * d) / den;
626  float arcLen1 = (a * e - b * d) / den;
627 
628  poca0 = P0 + arcLen0 * u0;
629  poca1 = P1 + arcLen1 * u1;
630  }
631  // Otherwise, take the poca to be the distance to the line at the second point
632  else {
633  float arcLenToNextPoint = w0.dot(u0);
634 
635  poca0 = P0 + arcLenToNextPoint * u0;
636  poca1 = P1;
637  }
638 
639  firstNextUnit = poca1 - poca0;
640 
641  float docaDist = firstNextUnit.norm();
642 
643  firstNextUnit = firstNextUnit.normalized();
644 
645  return docaDist;
646  }
Float_t den
Definition: plot.C:35
constexpr auto abs(T v)
Returns the absolute value of the argument.
Float_t d
Definition: plot.C:235
Float_t e
Definition: plot.C:35
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::ClusterMergeAlg::configure ( fhicl::ParameterSet const &  pset)
override

Definition at line 147 of file ClusterMergeAlg_tool.cc.

References dir, f1stDocaArcLRatHist, f1stTo2ndPosLenHist, f1stTo2ndPosLenRatHist, f1stTo2ndProjEigenHist, f2ndDocaArcLRatHist, f2ndTo1stProjEigenHist, fAxesDocaHist, fCosFirstAxisHist, fCosMaxFirstHist, fCosMaxNextHist, fCosNextAxisHist, fEnableMonitoring, fFirstEigenValueHists, fGapBetweenClusHist, fGapRatHist, fGapRatToLenHist, fMinEigenToProcess, fMinTransEigenVal, fNextEigenValueHists, fNumMergedClusters, fOutputHistograms, fProjEndPointLenHist, fProjEndPointRatHist, fRMaxFirstHist, fRMaxNextHist, fTimeToProcess, and fhicl::ParameterSet::get().

148  {
149  fEnableMonitoring = pset.get<bool>("EnableMonitoring", true);
150  fMinTransEigenVal = pset.get<float>("MinTransEigenVal", 0.09);
151  fMinEigenToProcess = pset.get<float>("MinEigenToProcess", 2.0);
152  fOutputHistograms = pset.get<bool>("OutputHistograms", false);
153 
154  fTimeToProcess = 0.;
155 
156  // If asked, define some histograms
157  if (fOutputHistograms) {
158  // Access ART's TFileService, which will handle creating and writing
159  // histograms and n-tuples for us.
161 
162  // Make a directory for these histograms
163  art::TFileDirectory dir = tfs->mkdir("MergeClusters");
164 
165  fFirstEigenValueHists.resize(3, nullptr);
166  fNextEigenValueHists.resize(3, nullptr);
167 
168  std::vector<float> maxValsVec = {20., 50., 250.};
169 
170  for (size_t idx : {0, 1, 2}) {
171  fFirstEigenValueHists[idx] =
172  dir.make<TH1F>(Form("FEigen1st%1zu", idx), "Eigen Val", 200, 0., maxValsVec[idx]);
173  fNextEigenValueHists[idx] =
174  dir.make<TH1F>(Form("FEigen2nd%1zu", idx), "Eigen Val", 200, 0., maxValsVec[idx]);
175  }
176 
177  fNumMergedClusters = dir.make<TH1F>("NumMergedClus", "Number Merged", 200, 0., 1000.);
178 
180  dir.make<TH1F>("1stTo2ndPosLen", "Distance between Clusters", 250, 0., 1000.);
181 
182  fRMaxFirstHist = dir.make<TH1F>("rMaxFirst", "Radius of First Cluster", 200, 0., 100.);
183  fCosMaxFirstHist = dir.make<TH1F>("CosMaxFirst", "Cos Angle First Cyl/Axis", 200, 0., 1.);
184  fCosFirstAxisHist = dir.make<TH1F>("CosFirstAxis", "Cos Angle First Next/Axis", 200, 0., 1.);
186  dir.make<TH1F>("1stTo2ndProjEigen", "Projected Distance First", 200, 0., 200.);
187 
188  fRMaxNextHist = dir.make<TH1F>("rMaxNext", "Radius of Next Cluster", 200, 0., 100.);
189  fCosMaxNextHist = dir.make<TH1F>("CosMaxNext", "Cos Angle Next Cyl/Axis", 200, 0., 1.);
190  fCosNextAxisHist = dir.make<TH1F>("CosNextAxis", "Cos Angle Next Next/Axis", 200, 0., 1.);
192  dir.make<TH1F>("2ndTo1stProjEigen", "Projected Distance Next", 200, 0., 200.);
193 
194  fGapBetweenClusHist = dir.make<TH1F>("ClusterGap", "Gap Between Clusters", 400, -200., 200.);
195  fGapRatToLenHist = dir.make<TH1F>("GapRatToLen", "Ratio Gap to Distance", 100, -8., 2.);
197  dir.make<TH1F>("ProjEndPointLen", "Projected End Point Len", 200, -100., 100.);
199  dir.make<TH1F>("ProjEndPointRat", "Projected End Point Ratio", 100, 0., 1.);
200 
201  fAxesDocaHist = dir.make<TH1F>("AxesDocaHist", "DOCA", 200, 0., 25.);
202  f1stDocaArcLRatHist = dir.make<TH1F>("ALenPOCA1Hist", "Arc Len to POCA 1", 400, -50., 50.);
203  f2ndDocaArcLRatHist = dir.make<TH1F>("ALenPOCA2Hist", "Arc Len to POCA 2", 400, -50., 50.);
204 
206  dir.make<TH1F>("1stTo2ndPosLenRat", "Ratio clus dist to eigen", 200., 0., 20.);
207  fGapRatHist = dir.make<TH1F>("GapRat", "Ratio Gap to Next Eigen", 400, -20., 20.);
208  }
209 
210  return;
211  }
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.
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.
TDirectory * dir
Definition: macro.C:5
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 648 of file ClusterMergeAlg_tool.cc.

Referenced by getTimeToExecute().

652  {
653  const reco::ClusterHit3D* nearestHit3D(hitList.front());
654  float closest(std::numeric_limits<float>::max());
655 
656  for (const auto& hit3D : hitList) {
657  Eigen::Vector3f refToHitVec = hit3D->getPosition() - refPoint;
658  float arcLenToHit = refToHitVec.dot(refVector);
659 
660  if (arcLenToHit < closest) {
661  nearestHit3D = hit3D;
662  closest = arcLenToHit;
663  }
664  }
665 
666  return nearestHit3D;
667  }
const reco::ClusterHit3D * lar_cluster3d::ClusterMergeAlg::findFurthestHit3D ( const Eigen::Vector3f &  refPoint,
const Eigen::Vector3f &  refVector,
const reco::HitPairListPtr hitList 
) const
private

Definition at line 669 of file ClusterMergeAlg_tool.cc.

References DEFINE_ART_CLASS_TOOL.

Referenced by getTimeToExecute().

673  {
674  const reco::ClusterHit3D* nearestHit3D(hitList.front());
675  float furthest(-std::numeric_limits<float>::max());
676 
677  for (const auto& hit3D : hitList) {
678  Eigen::Vector3f refToHitVec = hit3D->getPosition() - refPoint;
679  float arcLenToHit = refToHitVec.dot(refVector);
680 
681  if (arcLenToHit > furthest) {
682  nearestHit3D = hit3D;
683  furthest = arcLenToHit;
684  }
685  }
686 
687  return nearestHit3D;
688  }
float lar_cluster3d::ClusterMergeAlg::getTimeToExecute ( ) const
inlineoverridevirtual

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

Implements lar_cluster3d::IClusterModAlg.

Definition at line 69 of file ClusterMergeAlg_tool.cc.

References closestApproach(), findClosestHit3D(), findFurthestHit3D(), fTimeToProcess, linearClusters(), and mergeClusters().

69 { 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 213 of file ClusterMergeAlg_tool.cc.

214  {
215  return;
216  }
bool lar_cluster3d::ClusterMergeAlg::linearClusters ( reco::ClusterParameters firstCluster,
reco::ClusterParameters nextCluster 
) const
private

Definition at line 338 of file ClusterMergeAlg_tool.cc.

References util::abs(), closestApproach(), geo::vect::dot(), f1stDocaArcLRatHist, f1stTo2ndPosLenHist, f1stTo2ndPosLenRatHist, f1stTo2ndProjEigenHist, f2ndDocaArcLRatHist, f2ndTo1stProjEigenHist, fAxesDocaHist, fCosFirstAxisHist, fCosMaxFirstHist, fCosMaxNextHist, fCosNextAxisHist, fGapBetweenClusHist, Fill(), fMinTransEigenVal, fNextEigenValueHists, fOutputHistograms, fProjEndPointLenHist, fProjEndPointRatHist, fRMaxFirstHist, fRMaxNextHist, reco::PrincipalComponents::getAvePosition(), reco::PrincipalComponents::getEigenValues(), reco::PrincipalComponents::getEigenVectors(), and reco::ClusterParameters::getFullPCA().

Referenced by getTimeToExecute(), and ModifyClusters().

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

Definition at line 565 of file ClusterMergeAlg_tool.cc.

References fPCAAlg, reco::ClusterParameters::getFullPCA(), reco::ClusterParameters::getHit3DToEdgeMap(), reco::ClusterParameters::getHitPairListPtr(), reco::ClusterParameters::getSkeletonPCA(), reco::PrincipalComponents::getSvdOK(), lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_3D(), and reco::ClusterParameters::UpdateParameters().

Referenced by getTimeToExecute(), and ModifyClusters().

567  {
568  bool merged(false);
569 
570  // Merge the next cluster into the first one
571  // Get the hits
572  reco::HitPairListPtr& hitPairListPtr = firstClusterParams.getHitPairListPtr();
573 
574  // We copy the hits from the old to new but note that we need to update the parameters for each 2D hit we add
575  for (const auto* hit : nextClusterParams.getHitPairListPtr()) {
576  hitPairListPtr.push_back(hit);
577 
578  for (const auto* hit2D : hit->getHits())
579  if (hit2D) firstClusterParams.UpdateParameters(hit2D);
580  }
581 
582  // Recalculate the PCA
583  fPCAAlg.PCAAnalysis_3D(firstClusterParams.getHitPairListPtr(), firstClusterParams.getFullPCA());
584 
585  // Must have a valid pca
586  if (firstClusterParams.getFullPCA().getSvdOK()) {
587  // Finish out the merging here
588  reco::Hit3DToEdgeMap& firstEdgeMap = firstClusterParams.getHit3DToEdgeMap();
589  reco::Hit3DToEdgeMap& nextEdgeMap = nextClusterParams.getHit3DToEdgeMap();
590 
591  for (const auto& pair : nextEdgeMap)
592  firstEdgeMap[pair.first] = pair.second;
593 
594  // Set the skeleton PCA to make sure it has some value
595  firstClusterParams.getSkeletonPCA() = firstClusterParams.getFullPCA();
596 
597  // Zap the cluster we merged into the new one...
598  nextClusterParams = reco::ClusterParameters();
599 
600  merged = true;
601  }
602 
603  return merged;
604  }
bool getSvdOK() const
Definition: Cluster3D.h:240
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
reco::PrincipalComponents & getSkeletonPCA()
Definition: Cluster3D.h:465
reco::Hit3DToEdgeMap & getHit3DToEdgeMap()
Definition: Cluster3D.h:466
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:463
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:464
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:326
void UpdateParameters(const reco::ClusterHit2D *hit)
Definition: Cluster3D.h:440
Detector simulation of raw signals on wires.
std::unordered_map< const reco::ClusterHit3D *, reco::EdgeList > Hit3DToEdgeMap
Definition: Cluster3D.h:339
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 218 of file ClusterMergeAlg_tool.cc.

References fEnableMonitoring, fFirstEigenValueHists, Fill(), fMinEigenToProcess, fMinTransEigenVal, fNumMergedClusters, fOutputHistograms, fTimeToProcess, reco::PrincipalComponents::getEigenValues(), reco::ClusterParameters::getFullPCA(), art::left(), linearClusters(), mergeClusters(), and art::right().

219  {
227  // Initial clustering is done, now trim the list and get output parameters
228  cet::cpu_timer theClockBuildClusters;
229 
230  // Start clocks if requested
231  if (fEnableMonitoring) theClockBuildClusters.start();
232 
233  // Resort by the largest first eigen value (so the "longest" cluster)
234  clusterParametersList.sort([](auto& left, auto& right) {
235  return left.getFullPCA().getEigenValues()[2] > right.getFullPCA().getEigenValues()[2];
236  });
237 
238  // The idea is to continually loop through all clusters until we get to the point where we are no longer doing any merging.
239  // If two clusters are merged then we need to recycle through again because it may be that the new cluster can match when
240  // it might not have in the past
241  size_t lastClusterListCount = clusterParametersList.size() + 1;
242  reco::ClusterParametersList::iterator lastFirstClusterItr = clusterParametersList.begin();
243 
244  int numMergedClusters(0);
245  int nOutsideLoops(0);
246 
247  while (clusterParametersList.size() != lastClusterListCount) {
248  // Update the last count
249  lastClusterListCount = clusterParametersList.size();
250 
251  // Keep track of the first cluster iterator each pass through
252  reco::ClusterParametersList::iterator firstClusterItr = lastFirstClusterItr++;
253 
254  // Loop through the clusters
255  while (firstClusterItr != clusterParametersList.end()) {
256  reco::ClusterParameters& firstClusterParams = *firstClusterItr;
257  reco::ClusterParametersList::iterator nextClusterItr = firstClusterItr;
258 
259  // Take a brief interlude to do some histogramming
260  if (fOutputHistograms) {
261  const reco::PrincipalComponents& firstPCA = firstClusterParams.getFullPCA();
262 
263  Eigen::Vector3f firstEigenVals(
264  std::min(1.5 * std::sqrt(std::max(firstPCA.getEigenValues()[0], fMinTransEigenVal)),
265  50.),
266  std::min(1.5 * std::sqrt(std::max(firstPCA.getEigenValues()[1], fMinTransEigenVal)),
267  100.),
268  1.5 * std::sqrt(firstPCA.getEigenValues()[2]));
269 
270  for (size_t idx = 0; idx < 3; idx++)
271  fFirstEigenValueHists[idx]->Fill(firstEigenVals[idx], 1.);
272  }
273 
274  // Once you get down to the smallest clusters if they haven't already been absorbed there is no need to check them
275  if (firstClusterParams.getFullPCA().getEigenValues()[2] < fMinEigenToProcess) break;
276 
277  while (++nextClusterItr != clusterParametersList.end()) {
278  reco::ClusterParameters& nextClusterParams = *nextClusterItr;
279 
280  // On any given loop through here it **might** be that the first cluster has been modified. So can't cache
281  // the parameters, need the curret ones
282  if (linearClusters(firstClusterParams, nextClusterParams)) {
283  if (mergeClusters(firstClusterParams, nextClusterParams)) {
284  // Now remove the "next" cluster
285  nextClusterItr = clusterParametersList.erase(nextClusterItr);
286 
287  // Our new cluster may be larger than those before it so we should try to move backwards to make sure to
288  // give now smaller clusters the chance to get merged as well
289  reco::ClusterParametersList::iterator biggestItr = firstClusterItr;
290 
291  // Step backwards until we hit the beginning of the list
292  while (biggestItr-- != clusterParametersList.begin()) {
293  // The list has already been sorted largest to smallest so if we find a cluster that is "larger" then
294  // we have hit the limit
295  if ((*biggestItr).getFullPCA().getEigenValues()[2] >
296  (*firstClusterItr).getFullPCA().getEigenValues()[2]) {
297  // Want to insert after the cluster with the larger primary axes.. but there is
298  // no point in doing anything if the new cluster is already in the right spot
299  if (++biggestItr != firstClusterItr)
300  clusterParametersList.splice(
301  biggestItr, clusterParametersList, firstClusterItr);
302 
303  break;
304  }
305  }
306 
307  // Restart loop?
308  nextClusterItr = firstClusterItr;
309 
310  numMergedClusters++;
311  }
312  }
313  }
314 
315  firstClusterItr++;
316  }
317 
318  nOutsideLoops++;
319  }
320 
321  std::cout << "==> # merged: " << numMergedClusters << ", in " << nOutsideLoops
322  << " outside loops " << std::endl;
323 
324  if (fOutputHistograms) fNumMergedClusters->Fill(numMergedClusters, 1.);
325 
326  if (fEnableMonitoring) {
327  theClockBuildClusters.stop();
328 
329  fTimeToProcess = theClockBuildClusters.accumulated_real_time();
330  }
331 
332  mf::LogDebug("Cluster3D") << ">>>>> Merge clusters done, found " << clusterParametersList.size()
333  << " clusters" << std::endl;
334 
335  return;
336  }
intermediate_table::iterator iterator
std::vector< TH1F * > fFirstEigenValueHists
First Cluster eigen value.
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:102
TNtupleSim Fill(f1, f2, f3, f4)
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:242
bool mergeClusters(reco::ClusterParameters &, reco::ClusterParameters &) const
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:464
bool fEnableMonitoring
Data members to follow.
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.
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:94
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug

Member Data Documentation

TH1F* lar_cluster3d::ClusterMergeAlg::f1stDocaArcLRatHist
private

arc length to POCA for DOCA first cluster

Definition at line 126 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::f1stTo2ndPosLenHist
private

Distance between cluster centers.

Definition at line 106 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::f1stTo2ndPosLenRatHist
private

Ratio of distance between centers and first proj eigen.

Definition at line 129 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::f1stTo2ndProjEigenHist
private

arc length along vector between centers from first center to cylinder

Definition at line 112 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::f2ndDocaArcLRatHist
private

arc length to POCA for DOCA second cluster

Definition at line 127 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::f2ndTo1stProjEigenHist
private

arc length along vector between centers from next center to cylinder

Definition at line 118 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::fAxesDocaHist
private

Closest distance between two primary axes.

Definition at line 125 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::fCosFirstAxisHist
private

Cos angle between vector between centers and first axis.

Definition at line 110 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::fCosMaxFirstHist
private

Cos angle beteeen cylinder axis and edge.

Definition at line 109 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::fCosMaxNextHist
private

Cos angle beteeen cylinder axis and edge.

Definition at line 115 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::fCosNextAxisHist
private

Cos angle between vector between centers and next axis.

Definition at line 116 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

bool lar_cluster3d::ClusterMergeAlg::fEnableMonitoring
private

Data members to follow.

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

Definition at line 95 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and ModifyClusters().

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

First Cluster eigen value.

Definition at line 102 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and ModifyClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::fGapBetweenClusHist
private

Gap between clusters.

Definition at line 120 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::fGapRatHist
private

Ratio of gap and next proj eigen.

Definition at line 130 of file ClusterMergeAlg_tool.cc.

Referenced by configure().

TH1F* lar_cluster3d::ClusterMergeAlg::fGapRatToLenHist
private

Ratio of gap to distance between centers.

Definition at line 121 of file ClusterMergeAlg_tool.cc.

Referenced by configure().

float lar_cluster3d::ClusterMergeAlg::fMinEigenToProcess
private

Don't look anymore at clusters below this size.

Definition at line 97 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and ModifyClusters().

float lar_cluster3d::ClusterMergeAlg::fMinTransEigenVal
private

Set a mininum allowed value for the transverse eigen values.

Definition at line 96 of file ClusterMergeAlg_tool.cc.

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

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

Next Cluster eigen value.

Definition at line 103 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::fNumMergedClusters
private

How many clusters were merged?

Definition at line 104 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and ModifyClusters().

bool lar_cluster3d::ClusterMergeAlg::fOutputHistograms
private

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

Definition at line 98 of file ClusterMergeAlg_tool.cc.

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

PrincipalComponentsAlg lar_cluster3d::ClusterMergeAlg::fPCAAlg
private

Definition at line 132 of file ClusterMergeAlg_tool.cc.

Referenced by mergeClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::fProjEndPointLenHist
private

Projection of vector between the endpoints.

Definition at line 122 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::fProjEndPointRatHist
private

Ratio of projection to vector length.

Definition at line 123 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::fRMaxFirstHist
private

radius of "cylinder" first cluster

Definition at line 108 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

TH1F* lar_cluster3d::ClusterMergeAlg::fRMaxNextHist
private

radius of "cylinder" next cluster

Definition at line 114 of file ClusterMergeAlg_tool.cc.

Referenced by configure(), and linearClusters().

float lar_cluster3d::ClusterMergeAlg::fTimeToProcess
mutableprivate

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

Definition at line 100 of file ClusterMergeAlg_tool.cc.

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


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