Public Member Functions | Private Member Functions | Private Attributes | List of all members
lar_cluster3d::PrincipalComponentsAlg Class Reference

Cluster3D class. More...

#include <PrincipalComponentsAlg.h>

Public Member Functions

 PrincipalComponentsAlg (fhicl::ParameterSet const &pset)
 Constructor. More...
 
virtual ~PrincipalComponentsAlg ()
 Destructor. More...
 
void reconfigure (fhicl::ParameterSet const &pset)
 a handler for the case where the algorithm control parameters are to be reset More...
 
void PCAAnalysis (const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, double doca3DScl=3.) const
 Run the Principal Components Analysis. More...
 
void PCAAnalysis_3D (const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
 
void PCAAnalysis_2D (const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, bool updateAvePos=false) const
 
void PCAAnalysis_calc3DDocas (const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca) const
 
void PCAAnalysis_calc2DDocas (const reco::Hit2DListPtr &hit2DVector, const reco::PrincipalComponents &pca) const
 
int PCAAnalysis_reject2DOutliers (const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, double aveHitDoca) const
 
int PCAAnalysis_reject3DOutliers (const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca, double aveHitDoca) const
 
 PrincipalComponentsAlg (fhicl::ParameterSet const &pset)
 Constructor. More...
 
void PCAAnalysis (const detinfo::DetectorPropertiesData &detProp, const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, float doca3DScl=3.) const
 Run the Principal Components Analysis. More...
 
void PCAAnalysis_3D (const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
 
void PCAAnalysis_2D (const detinfo::DetectorPropertiesData &detProp, const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, bool updateAvePos=false) const
 
void PCAAnalysis_calc3DDocas (const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca) const
 
void PCAAnalysis_calc2DDocas (const reco::Hit2DListPtr &hit2DVector, const reco::PrincipalComponents &pca) const
 
int PCAAnalysis_reject2DOutliers (const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, float aveHitDoca) const
 
int PCAAnalysis_reject3DOutliers (const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca, float aveHitDoca) const
 

Private Member Functions

void getHit2DPocaToAxis (const TVector3 &axisPos, const TVector3 &axisDir, const reco::ClusterHit2D *hit2D, TVector3 &poca, double &arcLenAxis, double &arcLenWire, double &doca)
 This is used to get the poca, doca and arclen along cluster axis to 2D hit. More...
 

Private Attributes

double m_parallel
 means lines are parallel More...
 
geo::Geometrym_geometry
 
const detinfo::DetectorPropertiesm_detector
 
float m_parallel
 means lines are parallel More...
 
const geo::Geometrym_geometry
 

Detailed Description

Cluster3D class.

Definition at line 37 of file PrincipalComponentsAlg.h.

Constructor & Destructor Documentation

lar_cluster3d::PrincipalComponentsAlg::PrincipalComponentsAlg ( fhicl::ParameterSet const &  pset)

Constructor.

Parameters
pset

Definition at line 41 of file PrincipalComponentsAlg.cxx.

42 {
43  this->reconfigure(pset);
44 }
void reconfigure(fhicl::ParameterSet const &pset)
a handler for the case where the algorithm control parameters are to be reset
lar_cluster3d::PrincipalComponentsAlg::~PrincipalComponentsAlg ( )
virtual

Destructor.

Definition at line 48 of file PrincipalComponentsAlg.cxx.

49 {
50 }
lar_cluster3d::PrincipalComponentsAlg::PrincipalComponentsAlg ( fhicl::ParameterSet const &  pset)

Constructor.

Parameters
pset

Member Function Documentation

void lar_cluster3d::PrincipalComponentsAlg::getHit2DPocaToAxis ( const TVector3 &  axisPos,
const TVector3 &  axisDir,
const reco::ClusterHit2D hit2D,
TVector3 &  poca,
double &  arcLenAxis,
double &  arcLenWire,
double &  doca 
)
private

This is used to get the poca, doca and arclen along cluster axis to 2D hit.

Definition at line 60 of file PrincipalComponentsAlg.cxx.

67 {
68  // Step one is to set up to determine the point of closest approach of this 2D hit to
69  // the cluster's current axis.
70  // Get this wire's geometry object
71  const geo::WireID& hitID = hit2D->getHit().WireID();
72  const geo::WireGeo& wire_geom = m_geometry->WireIDToWireGeo(hitID);
73 
74  // From this, get the parameters of the line for the wire
75  double wirePos[3] = {0.,0.,0.};
76  TVector3 wireDir(wire_geom.Direction());
77 
78  wire_geom.GetCenter(wirePos);
79 
80  // Correct the wire position in x to set to correspond to the drift time
81  double hitPeak(hit2D->getHit().PeakTime());
82 
83  wirePos[0] = m_detector->ConvertTicksToX(hitPeak, hitID.Plane, hitID.TPC, hitID.Cryostat);
84 
85  // Get a vector from the wire position to our cluster's current average position
86  TVector3 wVec(axisPos.X()-wirePos[0], axisPos.Y()-wirePos[1], axisPos.Z()-wirePos[2]);
87 
88  // Get the products we need to compute the arc lengths to the distance of closest approach
89  double a(axisDir.Dot(axisDir));
90  double b(axisDir.Dot(wireDir));
91  double c(wireDir.Dot(wireDir));
92  double d(axisDir.Dot(wVec));
93  double e(wireDir.Dot(wVec));
94 
95  double den(a*c - b*b);
96 
97  // Parallel lines is a special case
98  if (fabs(den) > m_parallel)
99  {
100  arcLenAxis = (b*e - c*d) / den;
101  arcLenWire = (a*e - b*d) / den;
102  }
103  else
104  {
105  mf::LogDebug("Cluster3D") << "** Parallel lines, need a solution here" << std::endl;
106  arcLenAxis = 0.;
107  arcLenWire = 0.;
108  }
109 
110  // Now get the hit position we'll use for the pca analysis
111  poca = TVector3(wirePos[0] + arcLenWire * wireDir[0],
112  wirePos[1] + arcLenWire * wireDir[1],
113  wirePos[2] + arcLenWire * wireDir[2]);
114  TVector3 axisPocaPos(axisPos[0] + arcLenAxis * axisDir[0],
115  axisPos[1] + arcLenAxis * axisDir[1],
116  axisPos[2] + arcLenAxis * axisDir[2]);
117 
118  double deltaX(poca.X() - axisPocaPos.X());
119  double deltaY(poca.Y() - axisPocaPos.Y());
120  double deltaZ(poca.Z() - axisPocaPos.Z());
121  double doca2(deltaX*deltaX + deltaY*deltaY + deltaZ*deltaZ);
122 
123  doca = sqrt(doca2);
124 
125  return;
126 }
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
Definition: WireGeo.h:65
geo::WireID WireID() const
Definition: Hit.h:233
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
const recob::Hit * getHit() const
Definition: Cluster3D.h:78
const double e
const double a
double m_parallel
means lines are parallel
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
Vector Direction() const
Definition: WireGeo.h:587
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:218
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
static bool * b
Definition: config.cpp:1043
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:73
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
const detinfo::DetectorProperties * m_detector
QTextStream & endl(QTextStream &s)
WireGeo const & WireIDToWireGeo(geo::WireID const &wireid) const
void lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis ( const detinfo::DetectorPropertiesData detProp,
const reco::HitPairListPtr hitPairVector,
reco::PrincipalComponents pca,
float  doca3DScl = 3. 
) const

Run the Principal Components Analysis.

Definition at line 71 of file PrincipalComponentsAlg.cxx.

75  {
76  // This is the controlling outside function for running
77  // a Principal Components Analysis on the hits in our
78  // input cluster.
79  // There is a bootstrap process to be followed
80  // 1) Get the initial results from all 3D hits associated
81  // with the cluster
82  // 2) Refine the axis by using only the 2D hits on wires
83 
84  // Get the first axis from all 3D hits
85  PCAAnalysis_3D(hitPairVector, pca);
86 
87  // Make sure first pass was good
88  if (!pca.getSvdOK()) return;
89 
90  // First attempt to refine it using only 2D information
91  reco::PrincipalComponents pcaLoop = pca;
92 
93  PCAAnalysis_2D(detProp, hitPairVector, pcaLoop);
94 
95  // If valid result then go to next steps
96  if (pcaLoop.getSvdOK()) {
97  // Let's check the angle between the original and the updated axis
98  float cosAngle = pcaLoop.getEigenVectors().row(0) * pca.getEigenVectors().row(0).transpose();
99 
100  // Set the scale factor for the outlier rejection
101  float sclFctr(3.);
102 
103  // If we had a significant change then let's do some outlier rejection, etc.
104  if (cosAngle < 1.0) // pretty much everyone takes a turn
105  {
106  int maxIterations(3);
107  float maxRange = 3. * sqrt(pcaLoop.getEigenValues()[1]);
108  float aveDoca = pcaLoop.getAveHitDoca(); // was 0.2
109 
110  maxRange = sclFctr * 0.5 * (maxRange + aveDoca); // was std::max(maxRange, aveDoca);
111 
112  int numRejHits = PCAAnalysis_reject2DOutliers(hitPairVector, pcaLoop, maxRange);
113  int totalRejects(numRejHits);
114  int maxRejects(0.4 * hitPairVector.size());
115 
116  // Try looping to see if we improve things
117  while (maxIterations-- && numRejHits > 0 && totalRejects < maxRejects) {
118  // Run the PCA
119  PCAAnalysis_2D(detProp, hitPairVector, pcaLoop, true);
120 
121  maxRange =
122  sclFctr * 0.5 * (3. * sqrt(pcaLoop.getEigenValues()[1]) + pcaLoop.getAveHitDoca());
123 
124  numRejHits = PCAAnalysis_reject2DOutliers(hitPairVector, pcaLoop, maxRange);
125  }
126  }
127 
128  // Ok at this stage copy the latest results back into the cluster
129  pca = pcaLoop;
130 
131  // Now we make one last pass through the 3D hits to reject outliers there
132  PCAAnalysis_reject3DOutliers(hitPairVector, pca, doca3DScl * pca.getAveHitDoca());
133  }
134  else
135  pca = pcaLoop;
136 
137  return;
138  }
void PCAAnalysis_2D(const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, bool updateAvePos=false) const
bool getSvdOK() const
Definition: Cluster3D.h:244
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
int PCAAnalysis_reject2DOutliers(const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, double aveHitDoca) const
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:246
int PCAAnalysis_reject3DOutliers(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca, double aveHitDoca) const
const float getAveHitDoca() const
Definition: Cluster3D.h:249
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
void lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis ( const reco::HitPairListPtr hitPairVector,
reco::PrincipalComponents pca,
double  doca3DScl = 3. 
) const

Run the Principal Components Analysis.

Definition at line 156 of file PrincipalComponentsAlg.cxx.

157 {
158  // This is the controlling outside function for running
159  // a Principal Components Analysis on the hits in our
160  // input cluster.
161  // There is a bootstrap process to be followed
162  // 1) Get the initial results from all 3D hits associated
163  // with the cluster
164  // 2) Refine the axis by using only the 2D hits on wires
165 
166  // Get the first axis from all 3D hits
167  PCAAnalysis_3D(hitPairVector, pca);
168 
169  // Make sure first pass was good
170  if (!pca.getSvdOK()) return;
171 
172  // First attempt to refine it using only 2D information
173  reco::PrincipalComponents pcaLoop = pca;
174 
175  PCAAnalysis_2D(hitPairVector, pcaLoop);
176 
177  // If valid result then go to next steps
178  if (pcaLoop.getSvdOK())
179  {
180  // Let's check the angle between the original and the updated axis
181  double cosAngle = pcaLoop.getEigenVectors()[0][0] * pca.getEigenVectors()[0][0]
182  + pcaLoop.getEigenVectors()[0][1] * pca.getEigenVectors()[0][1]
183  + pcaLoop.getEigenVectors()[0][2] * pca.getEigenVectors()[0][2];
184 
185  // Set the scale factor for the outlier rejection
186  double sclFctr(3.);
187 
188  // If we had a significant change then let's do some outlier rejection, etc.
189  if (cosAngle < 1.0) // pretty much everyone takes a turn
190  {
191  int maxIterations(3);
192  double maxRange = 3.*sqrt(pcaLoop.getEigenValues()[1]);
193  double aveDoca = pcaLoop.getAveHitDoca(); // was 0.2
194 
195  maxRange = sclFctr * 0.5*(maxRange+aveDoca); // was std::max(maxRange, aveDoca);
196 
197  int numRejHits = PCAAnalysis_reject2DOutliers(hitPairVector, pcaLoop, maxRange);
198  int totalRejects(numRejHits);
199  int maxRejects(0.4*hitPairVector.size());
200 
201  // Try looping to see if we improve things
202  while(maxIterations-- && numRejHits > 0 && totalRejects < maxRejects)
203  {
204  // Run the PCA
205  PCAAnalysis_2D(hitPairVector, pcaLoop, true);
206 
207  maxRange = sclFctr * 0.5*(3.*sqrt(pcaLoop.getEigenValues()[1])+pcaLoop.getAveHitDoca());
208 
209  numRejHits = PCAAnalysis_reject2DOutliers(hitPairVector, pcaLoop, maxRange);
210  }
211 
212  }
213 
214  // Ok at this stage copy the latest results back into the cluster
215  pca = pcaLoop;
216 
217  // Now we make one last pass through the 3D hits to reject outliers there
218  PCAAnalysis_reject3DOutliers(hitPairVector, pca, doca3DScl * pca.getAveHitDoca());
219  }
220  else pca = pcaLoop;
221 
222  return;
223 }
void PCAAnalysis_2D(const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, bool updateAvePos=false) const
bool getSvdOK() const
Definition: Cluster3D.h:244
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
int PCAAnalysis_reject2DOutliers(const reco::HitPairListPtr &hitPairVector, reco::PrincipalComponents &pca, double aveHitDoca) const
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:246
int PCAAnalysis_reject3DOutliers(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca, double aveHitDoca) const
const float getAveHitDoca() const
Definition: Cluster3D.h:249
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
void lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_2D ( const detinfo::DetectorPropertiesData detProp,
const reco::HitPairListPtr hitPairVector,
reco::PrincipalComponents pca,
bool  updateAvePos = false 
) const

Definition at line 287 of file PrincipalComponentsAlg.cxx.

291  {
292  // Once an axis has been found our goal is to refine it by using only the 2D hits
293  // We'll get 3D information for each of these by using the axis as a reference and use
294  // the point of closest approach as the 3D position
295 
296  // Define elements of our covariance matrix
297  float xi2(0.);
298  float xiyi(0.);
299  float xizi(0.);
300  float yi2(0.);
301  float yizi(0.);
302  float zi2(0.);
303 
304  float aveHitDoca(0.);
305  Eigen::Vector3f avePosUpdate(0., 0., 0.);
306  int nHits(0);
307 
308  // Recover existing line parameters for current cluster
309  const reco::PrincipalComponents& inputPca = pca;
310  Eigen::Vector3f avePosition(inputPca.getAvePosition());
311  Eigen::Vector3f axisDirVec(inputPca.getEigenVectors().row(0));
312 
313  // We float loop here so we can use this method for both the first time through
314  // and a second time through where we re-calculate the mean position
315  // So, we need to keep track of the poca which we do with a float vector
316  std::vector<Eigen::Vector3f> hitPosVec;
317 
318  // Outer loop over 3D hits
319  for (const auto& hit3D : hitPairVector) {
320  // Inner loop over 2D hits
321  for (const auto& hit : hit3D->getHits()) {
322  // Step one is to set up to determine the point of closest approach of this 2D hit to
323  // the cluster's current axis.
324  // Get this wire's geometry object
325  const geo::WireID& hitID = hit->WireID();
326  const geo::WireGeo& wire_geom = m_geometry->WireIDToWireGeo(hitID);
327 
328  // From this, get the parameters of the line for the wire
329  double wirePosArr[3] = {0., 0., 0.};
330  wire_geom.GetCenter(wirePosArr);
331 
332  Eigen::Vector3f wireCenter(wirePosArr[0], wirePosArr[1], wirePosArr[2]);
333  Eigen::Vector3f wireDirVec(
334  wire_geom.Direction().X(), wire_geom.Direction().Y(), wire_geom.Direction().Z());
335 
336  // Correct the wire position in x to set to correspond to the drift time
337  float hitPeak(hit->getHit()->PeakTime());
338 
339  Eigen::Vector3f wirePos(
340  detProp.ConvertTicksToX(hitPeak, hitID.Plane, hitID.TPC, hitID.Cryostat),
341  wireCenter[1],
342  wireCenter[2]);
343 
344  // Compute the wire plane normal for this view
345  Eigen::Vector3f xAxis(1., 0., 0.);
346  Eigen::Vector3f planeNormal =
347  xAxis.cross(wireDirVec); // This gives a normal vector in +z for a Y wire
348 
349  float docaInPlane(wirePos[0] - avePosition[0]);
350  float arcLenToPlane(0.);
351  float cosAxisToPlaneNormal = axisDirVec.dot(planeNormal);
352 
353  Eigen::Vector3f axisPlaneIntersection = wirePos;
354  Eigen::Vector3f hitPosTVec = wirePos;
355 
356  if (fabs(cosAxisToPlaneNormal) > 0.) {
357  Eigen::Vector3f deltaPos = wirePos - avePosition;
358 
359  arcLenToPlane = deltaPos.dot(planeNormal) / cosAxisToPlaneNormal;
360  axisPlaneIntersection = avePosition + arcLenToPlane * axisDirVec;
361  docaInPlane = wirePos[0] - axisPlaneIntersection[0];
362 
363  Eigen::Vector3f axisToInter = axisPlaneIntersection - wirePos;
364  float arcLenToDoca = axisToInter.dot(wireDirVec);
365 
366  hitPosTVec += arcLenToDoca * wireDirVec;
367  }
368 
369  // Get a vector from the wire position to our cluster's current average position
370  Eigen::Vector3f wVec = avePosition - wirePos;
371 
372  // Get the products we need to compute the arc lengths to the distance of closest approach
373  float a(axisDirVec.dot(axisDirVec));
374  float b(axisDirVec.dot(wireDirVec));
375  float c(wireDirVec.dot(wireDirVec));
376  float d(axisDirVec.dot(wVec));
377  float e(wireDirVec.dot(wVec));
378 
379  float den(a * c - b * b);
380  float arcLen1(0.);
381  float arcLen2(0.);
382 
383  // Parallel lines is a special case
384  if (fabs(den) > m_parallel) {
385  arcLen1 = (b * e - c * d) / den;
386  arcLen2 = (a * e - b * d) / den;
387  }
388  else {
389  mf::LogDebug("Cluster3D") << "** Parallel lines, need a solution here" << std::endl;
390  break;
391  }
392 
393  // Now get the hit position we'll use for the pca analysis
394  //float hitPos[] = {wirePos[0] + arcLen2 * wireDirVec[0],
395  // wirePos[1] + arcLen2 * wireDirVec[1],
396  // wirePos[2] + arcLen2 * wireDirVec[2]};
397  //float axisPos[] = {avePosition[0] + arcLen1 * axisDirVec[0],
398  // avePosition[1] + arcLen1 * axisDirVec[1],
399  // avePosition[2] + arcLen1 * axisDirVec[2]};
400  Eigen::Vector3f hitPos = wirePos + arcLen2 * wireDirVec;
401  Eigen::Vector3f axisPos = avePosition + arcLen1 * axisDirVec;
402  float deltaX = hitPos(0) - axisPos(0);
403  float deltaY = hitPos(1) - axisPos(1);
404  float deltaZ = hitPos(2) - axisPos(2);
405  float doca2 = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
406  float doca = sqrt(doca2);
407 
408  docaInPlane = doca;
409 
410  aveHitDoca += fabs(docaInPlane);
411 
412  //Eigen::Vector3f deltaPos = hitPos - hitPosTVec;
413  //float deltaDoca = doca - docaInPlane;
414 
415  //if (fabs(deltaPos[0]) > 1. || fabs(deltaPos[1]) > 1. || fabs(deltaPos[2]) > 1. || fabs(deltaDoca) > 2.)
416  //{
417  // std::cout << "**************************************************************************************" << std::endl;
418  // std::cout << "Diff in doca: " << deltaPos[0] << "," << deltaPos[1] << "," << deltaPos[2] << ", deltaDoca: " << deltaDoca << std::endl;
419  // std::cout << "-- HitPosTVec: " << hitPosTVec[0] << "," << hitPosTVec[1] << "," << hitPosTVec[2] << std::endl;
420  // std::cout << "-- hitPos: " << hitPos[0] << "," << hitPos[1] << "," << hitPos[2] << std::endl;
421  // std::cout << "-- WirePos: " << wirePos[0] << "," << wirePos[1] << "," << wirePos[2] << std::endl;
422  //}
423 
424  // Set the hit's doca and arclen
425  hit->setDocaToAxis(fabs(docaInPlane));
426  hit->setArcLenToPoca(arcLenToPlane);
427 
428  // If this point is considered an outlier then we skip
429  // the accumulation for average position and covariance
430  if (hit->getStatusBits() & 0x80) { continue; }
431 
432  //hitPosTVec = hitPos;
433 
434  avePosUpdate += hitPosTVec;
435 
436  hitPosVec.push_back(hitPosTVec);
437 
438  nHits++;
439  }
440  }
441 
442  // Get updated average position
443  avePosUpdate /= float(nHits);
444 
445  // Get the average hit doca
446  aveHitDoca /= float(nHits);
447 
448  if (updateAvePos) { avePosition = avePosUpdate; }
449 
450  // Now loop through the hits and build out the covariance matrix
451  for (auto& hitPos : hitPosVec) {
452  // And increment the values in the covariance matrix
453  float x = hitPos[0] - avePosition[0];
454  float y = hitPos[1] - avePosition[1];
455  float z = hitPos[2] - avePosition[2];
456 
457  xi2 += x * x;
458  xiyi += x * y;
459  xizi += x * z;
460  yi2 += y * y;
461  yizi += y * z;
462  zi2 += z * z;
463  }
464 
465  // Accumulation done, now do the actual work
466 
467  // Using Eigen package
468  Eigen::Matrix3f sig;
469 
470  sig << xi2, xiyi, xizi, xiyi, yi2, yizi, xizi, yizi, zi2;
471 
472  sig *= 1. / (nHits - 1);
473 
474  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigenMat(sig);
475 
476  if (eigenMat.info() == Eigen::ComputationInfo::Success) {
477  // Now copy output
478  // The returned eigen values and vectors will be returned in an xyz system where x is the smallest spread,
479  // y is the next smallest and z is the largest. Adopt that convention going forward
480  reco::PrincipalComponents::EigenValues recobEigenVals = eigenMat.eigenvalues().cast<float>();
482  eigenMat.eigenvectors().transpose().cast<float>();
483 
484  // Store away
486  true, nHits, recobEigenVals, recobEigenVecs, avePosition, aveHitDoca);
487  }
488  else {
489  mf::LogDebug("Cluster3D") << "PCA decompose failure, numPairs = " << nHits << std::endl;
491  }
492 
493  return;
494  }
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
Definition: WireGeo.h:65
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
const double e
Eigen::Vector3f EigenValues
Definition: Cluster3D.h:226
const double a
const Eigen::Vector3f & getAvePosition() const
Definition: Cluster3D.h:248
double m_parallel
means lines are parallel
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
Vector Direction() const
Definition: WireGeo.h:587
Detector simulation of raw signals on wires.
double ConvertTicksToX(double ticks, int p, int t, int c) const
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
Eigen::Matrix3f EigenVectors
Definition: Cluster3D.h:227
static bool * b
Definition: config.cpp:1043
list x
Definition: train.py:276
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:73
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
QTextStream & endl(QTextStream &s)
WireGeo const & WireIDToWireGeo(geo::WireID const &wireid) const
void lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_2D ( const reco::HitPairListPtr hitPairVector,
reco::PrincipalComponents pca,
bool  updateAvePos = false 
) const

Definition at line 353 of file PrincipalComponentsAlg.cxx.

354 {
355  // Once an axis has been found our goal is to refine it by using only the 2D hits
356  // We'll get 3D information for each of these by using the axis as a reference and use
357  // the point of closest approach as the 3D position
358 
359  // Define elements of our covariance matrix
360  double xi2(0.);
361  double xiyi(0.);
362  double xizi(0.);
363  double yi2(0.);
364  double yizi(0.);
365  double zi2(0.);
366 
367  double aveHitDoca(0.);
368  TVector3 avePosUpdate(0.,0.,0.);
369  int nHits(0);
370 
371  // Recover existing line parameters for current cluster
372  const reco::PrincipalComponents& inputPca = pca;
373  TVector3 avePosition(inputPca.getAvePosition()[0], inputPca.getAvePosition()[1], inputPca.getAvePosition()[2]);
374  TVector3 axisDirVec(inputPca.getEigenVectors()[0][0], inputPca.getEigenVectors()[0][1], inputPca.getEigenVectors()[0][2]);
375 
376  // We double loop here so we can use this method for both the first time through
377  // and a second time through where we re-calculate the mean position
378  // So, we need to keep track of the poca which we do with a double vector
379  std::vector<TVector3> hitPosVec;
380 
381  // Outer loop over 3D hits
382  for (const auto& hit3D : hitPairVector)
383  {
384  // Inner loop over 2D hits
385  for (const auto& hit : hit3D->getHits())
386  {
387  // Step one is to set up to determine the point of closest approach of this 2D hit to
388  // the cluster's current axis.
389  // Get this wire's geometry object
390  const geo::WireID& hitID = hit->getHit().WireID();
391  const geo::WireGeo& wire_geom = m_geometry->WireIDToWireGeo(hitID);
392 
393  // From this, get the parameters of the line for the wire
394  double wirePosArr[3] = {0.,0.,0.};
395  wire_geom.GetCenter(wirePosArr);
396 
397  TVector3 wireCenter(wirePosArr[0], wirePosArr[1], wirePosArr[2]);
398  TVector3 wireDirVec(wire_geom.Direction());
399 
400  // Correct the wire position in x to set to correspond to the drift time
401  double hitPeak(hit->getHit().PeakTime());
402 
403  TVector3 wirePos(m_detector->ConvertTicksToX(hitPeak, hitID.Plane, hitID.TPC, hitID.Cryostat), wireCenter[1], wireCenter[2]);
404 
405  // Compute the wire plane normal for this view
406  TVector3 xAxis(1.,0.,0.);
407  TVector3 planeNormal = xAxis.Cross(wireDirVec); // This gives a normal vector in +z for a Y wire
408 
409  double docaInPlane(wirePos[0] - avePosition[0]);
410  double arcLenToPlane(0.);
411  double cosAxisToPlaneNormal = axisDirVec.Dot(planeNormal);
412 
413  TVector3 axisPlaneIntersection = wirePos;
414  TVector3 hitPosTVec = wirePos;
415 
416  if (fabs(cosAxisToPlaneNormal) > 0.)
417  {
418  TVector3 deltaPos = wirePos - avePosition;
419 
420  arcLenToPlane = deltaPos.Dot(planeNormal) / cosAxisToPlaneNormal;
421  axisPlaneIntersection = avePosition + arcLenToPlane * axisDirVec;
422  docaInPlane = wirePos[0] - axisPlaneIntersection[0];
423 
424  TVector3 axisToInter = axisPlaneIntersection - wirePos;
425  double arcLenToDoca = axisToInter.Dot(wireDirVec);
426 
427  hitPosTVec += arcLenToDoca * wireDirVec;
428  }
429 
430  // Get a vector from the wire position to our cluster's current average position
431  TVector3 wVec = avePosition - wirePos;
432 
433  // Get the products we need to compute the arc lengths to the distance of closest approach
434  double a(axisDirVec.Dot(axisDirVec));
435  double b(axisDirVec.Dot(wireDirVec));
436  double c(wireDirVec.Dot(wireDirVec));
437  double d(axisDirVec.Dot(wVec));
438  double e(wireDirVec.Dot(wVec));
439 
440  double den(a*c - b*b);
441  double arcLen1(0.);
442  double arcLen2(0.);
443 
444  // Parallel lines is a special case
445  if (fabs(den) > m_parallel)
446  {
447  arcLen1 = (b*e - c*d) / den;
448  arcLen2 = (a*e - b*d) / den;
449  }
450  else
451  {
452  mf::LogDebug("Cluster3D") << "** Parallel lines, need a solution here" << std::endl;
453  break;
454  }
455 
456  // Now get the hit position we'll use for the pca analysis
457  //double hitPos[] = {wirePos[0] + arcLen2 * wireDirVec[0],
458  // wirePos[1] + arcLen2 * wireDirVec[1],
459  // wirePos[2] + arcLen2 * wireDirVec[2]};
460  //double axisPos[] = {avePosition[0] + arcLen1 * axisDirVec[0],
461  // avePosition[1] + arcLen1 * axisDirVec[1],
462  // avePosition[2] + arcLen1 * axisDirVec[2]};
463  TVector3 hitPos = wirePos + arcLen2 * wireDirVec;
464  TVector3 axisPos = avePosition + arcLen1 * axisDirVec;
465  double deltaX = hitPos[0] - axisPos[0];
466  double deltaY = hitPos[1] - axisPos[1];
467  double deltaZ = hitPos[2] - axisPos[2];
468  double doca2 = deltaX*deltaX + deltaY*deltaY + deltaZ*deltaZ;
469  double doca = sqrt(doca2);
470 
471  docaInPlane = doca;
472 
473  aveHitDoca += fabs(docaInPlane);
474 
475  //TVector3 deltaPos = hitPos - hitPosTVec;
476  //double deltaDoca = doca - docaInPlane;
477 
478  //if (fabs(deltaPos[0]) > 1. || fabs(deltaPos[1]) > 1. || fabs(deltaPos[2]) > 1. || fabs(deltaDoca) > 2.)
479  //{
480  // std::cout << "**************************************************************************************" << std::endl;
481  // std::cout << "Diff in doca: " << deltaPos[0] << "," << deltaPos[1] << "," << deltaPos[2] << ", deltaDoca: " << deltaDoca << std::endl;
482  // std::cout << "-- HitPosTVec: " << hitPosTVec[0] << "," << hitPosTVec[1] << "," << hitPosTVec[2] << std::endl;
483  // std::cout << "-- hitPos: " << hitPos[0] << "," << hitPos[1] << "," << hitPos[2] << std::endl;
484  // std::cout << "-- WirePos: " << wirePos[0] << "," << wirePos[1] << "," << wirePos[2] << std::endl;
485  //}
486 
487  // Set the hit's doca and arclen
488  hit->setDocaToAxis(fabs(docaInPlane));
489  hit->setArcLenToPoca(arcLenToPlane);
490 
491  // If this point is considered an outlier then we skip
492  // the accumulation for average position and covariance
493  if (hit->getStatusBits() & 0x80)
494  {
495  continue;
496  }
497 
498  //hitPosTVec = hitPos;
499 
500  avePosUpdate += hitPosTVec;
501 
502  hitPosVec.push_back(hitPosTVec);
503 
504  nHits++;
505  }
506  }
507 
508  // Get updated average position
509  avePosUpdate[0] /= double(nHits);
510  avePosUpdate[1] /= double(nHits);
511  avePosUpdate[2] /= double(nHits);
512 
513  // Get the average hit doca
514  aveHitDoca /= double(nHits);
515 
516  if (updateAvePos)
517  {
518  avePosition = avePosUpdate;
519  }
520 
521  // Now loop through the hits and build out the covariance matrix
522  for(auto& hitPos : hitPosVec)
523  {
524  // And increment the values in the covariance matrix
525  double x = hitPos[0] - avePosition[0];
526  double y = hitPos[1] - avePosition[1];
527  double z = hitPos[2] - avePosition[2];
528 
529  xi2 += x * x;
530  xiyi += x * y;
531  xizi += x * z;
532  yi2 += y * y;
533  yizi += y * z;
534  zi2 += z * z;
535  }
536 
537  // Accumulation done, now do the actual work
538 
539  // Create the actual matrix
540  TMatrixD sigma(3, 3);
541 
542  sigma(0,0) = xi2;
543  sigma(0,1) = sigma(1,0) = xiyi;
544  sigma(0,2) = sigma(2,0) = xizi;
545  sigma(1,1) = yi2;
546  sigma(1,2) = sigma(2,1) = yizi;
547  sigma(2,2) = zi2;
548 
549  // Scale by number of pairs
550  sigma *= (1./(nHits - 1.));
551 
552  // Set up the SVD
553  TDecompSVD rootSVD(sigma);
554 
555  // run the decomposition
556  bool svdOk(false);
557 
558  try
559  {
560  svdOk = rootSVD.Decompose();
561  }
562  catch(...)
563  {
564  svdOk = false;
565  mf::LogDebug("Cluster3D") << "PCA decompose failure, nhits = " << nHits << std::endl;
566  }
567 
568  if (svdOk)
569  {
570  // Extract results
571  TVectorD eigenVals = rootSVD.GetSig();
572  TMatrixD eigenVecs = rootSVD.GetU();
573 
574  // Get the eigen values
575  double recobEigenVals[] = {eigenVals[0], eigenVals[1], eigenVals[2]};
576 
577  // Grab the principle axes
579  std::vector<double> tempVec;
580 
581  // Get the first column vector
582  tempVec.push_back(eigenVecs(0, 0));
583  tempVec.push_back(eigenVecs(1, 0));
584  tempVec.push_back(eigenVecs(2, 0));
585  recobEigenVecs.push_back(tempVec);
586 
587  // Now the second
588  tempVec.clear();
589  tempVec.push_back(eigenVecs(0, 1));
590  tempVec.push_back(eigenVecs(1, 1));
591  tempVec.push_back(eigenVecs(2, 1));
592  recobEigenVecs.push_back(tempVec);
593 
594  // And the last
595  tempVec.clear();
596  tempVec.push_back(eigenVecs(0, 2));
597  tempVec.push_back(eigenVecs(1, 2));
598  tempVec.push_back(eigenVecs(2, 2));
599  recobEigenVecs.push_back(tempVec);
600 
601  // Save the average position
602  double avePosToSave[] = {avePosition[0],avePosition[1],avePosition[2]};
603 
604  // Store away
605  pca = reco::PrincipalComponents(svdOk, nHits, recobEigenVals, recobEigenVecs, avePosToSave, aveHitDoca);
606  }
607  else
608  {
610  }
611 
612  return;
613 }
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
Definition: WireGeo.h:65
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
const double e
const double a
const Eigen::Vector3f & getAvePosition() const
Definition: Cluster3D.h:248
double m_parallel
means lines are parallel
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
Vector Direction() const
Definition: WireGeo.h:587
Detector simulation of raw signals on wires.
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
Eigen::Matrix3f EigenVectors
Definition: Cluster3D.h:227
static bool * b
Definition: config.cpp:1043
list x
Definition: train.py:276
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:73
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
const detinfo::DetectorProperties * m_detector
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
QTextStream & endl(QTextStream &s)
WireGeo const & WireIDToWireGeo(geo::WireID const &wireid) const
void lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_3D ( const reco::HitPairListPtr hitPairList,
reco::PrincipalComponents pca,
bool  skeletonOnly = false 
) const
void lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_3D ( const reco::HitPairListPtr hitPairList,
reco::PrincipalComponents pca,
bool  skeletonOnly = false 
) const

Definition at line 225 of file PrincipalComponentsAlg.cxx.

226 {
227  // We want to run a PCA on the input TkrVecPoints...
228  // The steps are:
229  // 1) do a mean normalization of the input vec points
230  // 2) compute the covariance matrix
231  // 3) run the SVD
232  // 4) extract the eigen vectors and values
233  // see what happens
234 
235  // Run through the HitPairList and get the mean position of all the hits
236  double meanPos[] = {0.,0.,0.};
237  int numPairsInt(0);
238 
239  for (const auto& hit : hitPairVector)
240  {
241  if (skeletonOnly && !((hit->getStatusBits() & 0x10000000) == 0x10000000)) continue;
242 
243  meanPos[0] += hit->getPosition()[0];
244  meanPos[1] += hit->getPosition()[1];
245  meanPos[2] += hit->getPosition()[2];
246  numPairsInt++;
247  }
248 
249  double numPairs = double(numPairsInt);
250 
251  meanPos[0] /= numPairs;
252  meanPos[1] /= numPairs;
253  meanPos[2] /= numPairs;
254 
255  // Define elements of our covariance matrix
256  double xi2 = 0.;
257  double xiyi = 0.;
258  double xizi = 0.;
259  double yi2 = 0.;
260  double yizi = 0.;
261  double zi2 = 0.;
262 
263  // Back through the hits to build the matrix
264  for (const auto& hit : hitPairVector)
265  {
266  if (skeletonOnly && !((hit->getStatusBits() & 0x10000000) == 0x10000000)) continue;
267 
268  double x = hit->getPosition()[0] - meanPos[0];
269  double y = hit->getPosition()[1] - meanPos[1];
270  double z = hit->getPosition()[2] - meanPos[2];
271 
272  xi2 += x * x;
273  xiyi += x * y;
274  xizi += x * z;
275  yi2 += y * y;
276  yizi += y * z;
277  zi2 += z * z;
278  }
279 
280  // Create the actual matrix
281  TMatrixD sigma(3, 3);
282 
283  sigma(0,0) = xi2;
284  sigma(0,1) = sigma(1,0) = xiyi;
285  sigma(0,2) = sigma(2,0) = xizi;
286  sigma(1,1) = yi2;
287  sigma(1,2) = sigma(2,1) = yizi;
288  sigma(2,2) = zi2;
289 
290  // Scale by number of pairs
291  sigma *= (1./(numPairs - 1.));
292 
293  // Set up the SVD
294  TDecompSVD rootSVD(sigma);
295 
296  // run the decomposition
297  bool svdOk(false);
298 
299  try
300  {
301  svdOk = rootSVD.Decompose();
302  }
303  catch(...)
304  {
305  svdOk = false;
306  mf::LogDebug("Cluster3D") << "PCA decompose failure, numPairs = " << numPairs << std::endl;
307  }
308 
309  if (svdOk)
310  {
311  // Extract results
312  TVectorD eigenVals = rootSVD.GetSig();
313  TMatrixD eigenVecs = rootSVD.GetU();
314 
315  // Get the eigen values
316  double recobEigenVals[] = {eigenVals[0], eigenVals[1], eigenVals[2]};
317 
318  // Grab the principle axes
320  std::vector<double> tempVec;
321 
322  // Get the first column vector
323  tempVec.push_back(eigenVecs(0, 0));
324  tempVec.push_back(eigenVecs(1, 0));
325  tempVec.push_back(eigenVecs(2, 0));
326  recobEigenVecs.push_back(tempVec);
327 
328  // Now the second
329  tempVec.clear();
330  tempVec.push_back(eigenVecs(0, 1));
331  tempVec.push_back(eigenVecs(1, 1));
332  tempVec.push_back(eigenVecs(2, 1));
333  recobEigenVecs.push_back(tempVec);
334 
335  // And the last
336  tempVec.clear();
337  tempVec.push_back(eigenVecs(0, 2));
338  tempVec.push_back(eigenVecs(1, 2));
339  tempVec.push_back(eigenVecs(2, 2));
340  recobEigenVecs.push_back(tempVec);
341 
342  // Store away
343  pca = reco::PrincipalComponents(svdOk, numPairsInt, recobEigenVals, recobEigenVecs, meanPos);
344  }
345  else
346  {
348  }
349 
350  return;
351 }
Detector simulation of raw signals on wires.
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
Eigen::Matrix3f EigenVectors
Definition: Cluster3D.h:227
list x
Definition: train.py:276
QTextStream & endl(QTextStream &s)
void lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_calc2DDocas ( const reco::Hit2DListPtr hit2DVector,
const reco::PrincipalComponents pca 
) const
void lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_calc2DDocas ( const reco::Hit2DListPtr hit2DVector,
const reco::PrincipalComponents pca 
) const

Definition at line 667 of file PrincipalComponentsAlg.cxx.

669 {
670  // Our mission, should we choose to accept it, is to scan through the 2D hits and reject
671  // any outliers. Basically, any hit outside a scaled range of the average doca from the
672  // first pass is marked by setting the bit in the status word.
673 
674  // We'll need the current PCA axis to determine doca and arclen
675  TVector3 avePosition(pca.getAvePosition()[0], pca.getAvePosition()[1], pca.getAvePosition()[2]);
676  TVector3 axisDirVec(pca.getEigenVectors()[0][0], pca.getEigenVectors()[0][1], pca.getEigenVectors()[0][2]);
677 
678  // Recover the principle eigen value for range constraints
679  double maxArcLen = 4.*sqrt(pca.getEigenValues()[0]);
680 
681  // We want to keep track of the average
682  double aveHitDoca(0.);
683 
684  // Outer loop over views
685  for (const auto* hit : hit2DListPtr)
686  {
687  // Step one is to set up to determine the point of closest approach of this 2D hit to
688  // the cluster's current axis. We do that by finding the point of intersection of the
689  // cluster's axis with a plane defined by the wire the hit is associated with.
690  // Get this wire's geometry object
691  const geo::WireID& hitID = hit->getHit().WireID();
692  const geo::WireGeo& wire_geom = m_geometry->WireIDToWireGeo(hitID);
693 
694  // From this, get the parameters of the line for the wire
695  double wirePosArr[3] = {0.,0.,0.};
696  wire_geom.GetCenter(wirePosArr);
697 
698  TVector3 wireCenter(wirePosArr[0], wirePosArr[1], wirePosArr[2]);
699  TVector3 wireDirVec(wire_geom.Direction());
700 
701  // Correct the wire position in x to set to correspond to the drift time
702  TVector3 wirePos(hit->getXPosition(), wireCenter[1], wireCenter[2]);
703 
704  // Compute the wire plane normal for this view
705  TVector3 xAxis(1.,0.,0.);
706  TVector3 planeNormal = xAxis.Cross(wireDirVec); // This gives a normal vector in +z for a Y wire
707 
708  double arcLenToPlane(0.);
709  double docaInPlane(wirePos[0] - avePosition[0]);
710  double cosAxisToPlaneNormal = axisDirVec.Dot(planeNormal);
711 
712  TVector3 axisPlaneIntersection = wirePos;
713 
714  // If current cluster axis is not parallel to wire plane then find intersection point
715  if (fabs(cosAxisToPlaneNormal) > 0.)
716  {
717  TVector3 deltaPos = wirePos - avePosition;
718 
719  arcLenToPlane = std::min(deltaPos.Dot(planeNormal) / cosAxisToPlaneNormal, maxArcLen);
720  axisPlaneIntersection = avePosition + arcLenToPlane * axisDirVec;
721  TVector3 axisToInter = axisPlaneIntersection - wirePos;
722  double arcLenToDoca = axisToInter.Dot(wireDirVec);
723 
724  // If the arc length along the wire to the poca is outside the TPC then reset
725  if (fabs(arcLenToDoca) > wire_geom.HalfL()) arcLenToDoca = wire_geom.HalfL();
726 
727  // If we were successful in getting to the wire plane then the doca is simply the
728  // difference in x coordinates... but we hvae to worry about the special cases so
729  // we calculate a 3D doca based on arclengths above...
730  TVector3 docaVec = axisPlaneIntersection - (wirePos + arcLenToDoca * wireDirVec);
731  docaInPlane = docaVec.Mag();
732  }
733 
734  aveHitDoca += fabs(docaInPlane);
735 
736  // Set the hit's doca and arclen
737  hit->setDocaToAxis(fabs(docaInPlane));
738  hit->setArcLenToPoca(arcLenToPlane);
739  }
740 
741  // Compute the average and store
742  aveHitDoca /= double(hit2DListPtr.size());
743 
744  pca.setAveHitDoca(aveHitDoca);
745 
746  return;
747 }
Geometry description of a TPC wireThe wire is a single straight segment on a wire plane...
Definition: WireGeo.h:65
void setAveHitDoca(double doca) const
Definition: Cluster3D.h:252
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:246
const Eigen::Vector3f & getAvePosition() const
Definition: Cluster3D.h:248
Vector Direction() const
Definition: WireGeo.h:587
Detector simulation of raw signals on wires.
double HalfL() const
Returns half the length of the wire [cm].
Definition: WireGeo.h:128
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:73
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
WireGeo const & WireIDToWireGeo(geo::WireID const &wireid) const
void lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_calc3DDocas ( const reco::HitPairListPtr hitPairVector,
const reco::PrincipalComponents pca 
) const
void lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_calc3DDocas ( const reco::HitPairListPtr hitPairVector,
const reco::PrincipalComponents pca 
) const

Definition at line 615 of file PrincipalComponentsAlg.cxx.

617 {
618  // Our mission, should we choose to accept it, is to scan through the 2D hits and reject
619  // any outliers. Basically, any hit outside a scaled range of the average doca from the
620  // first pass is marked by setting the bit in the status word.
621 
622  // We'll need the current PCA axis to determine doca and arclen
623  TVector3 avePosition(pca.getAvePosition()[0], pca.getAvePosition()[1], pca.getAvePosition()[2]);
624  TVector3 axisDirVec(pca.getEigenVectors()[0][0], pca.getEigenVectors()[0][1], pca.getEigenVectors()[0][2]);
625 
626  // We want to keep track of the average
627  double aveDoca3D(0.);
628 
629  // Outer loop over views
630  for (const auto* clusterHit3D : hitPairVector)
631  {
632  // Always reset the existing status bit
633  clusterHit3D->clearStatusBits(0x80);
634 
635  // Now we need to calculate the doca and poca...
636  // Start by getting this hits position
637  TVector3 clusPos(clusterHit3D->getPosition()[0],clusterHit3D->getPosition()[1],clusterHit3D->getPosition()[2]);
638 
639  // Form a TVector from this to the cluster average position
640  TVector3 clusToHitVec = clusPos - avePosition;
641 
642  // With this we can get the arclength to the doca point
643  double arclenToPoca = clusToHitVec.Dot(axisDirVec);
644 
645  // Get the coordinates along the axis for this point
646  TVector3 docaPos = avePosition + arclenToPoca * axisDirVec;
647 
648  // Now get doca and poca
649  TVector3 docaPosToClusPos = clusPos - docaPos;
650  double docaToAxis = docaPosToClusPos.Mag();
651 
652  aveDoca3D += docaToAxis;
653 
654  // Ok, set the values in the hit
655  clusterHit3D->setDocaToAxis(docaToAxis);
656  clusterHit3D->setArclenToPoca(arclenToPoca);
657  }
658 
659  // Compute the average and store
660  aveDoca3D /= double(hitPairVector.size());
661 
662  pca.setAveHitDoca(aveDoca3D);
663 
664  return;
665 }
void setAveHitDoca(double doca) const
Definition: Cluster3D.h:252
const Eigen::Vector3f & getAvePosition() const
Definition: Cluster3D.h:248
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
int lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_reject2DOutliers ( const reco::HitPairListPtr hitPairVector,
reco::PrincipalComponents pca,
float  aveHitDoca 
) const

Definition at line 638 of file PrincipalComponentsAlg.cxx.

641  {
642  // Our mission, should we choose to accept it, is to scan through the 2D hits and reject
643  // any outliers. Basically, any hit outside a scaled range of the average doca from the
644  // first pass is marked by setting the bit in the status word.
645 
646  // First get the average doca scaled by some appropriate factor
647  int numRejHits(0);
648 
649  // Outer loop over views
650  for (const auto& hit3D : hitPairVector) {
651  // Inner loop over hits in this view
652  for (const auto& hit : hit3D->getHits()) {
653  // Always reset the existing status bit
654  hit->clearStatusBits(0x80);
655 
656  if (hit->getDocaToAxis() > maxDocaAllowed) {
657  hit->setStatusBit(0x80);
658  numRejHits++;
659  }
660  }
661  }
662 
663  return numRejHits;
664  }
Detector simulation of raw signals on wires.
int lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_reject2DOutliers ( const reco::HitPairListPtr hitPairVector,
reco::PrincipalComponents pca,
double  aveHitDoca 
) const

Definition at line 749 of file PrincipalComponentsAlg.cxx.

752 {
753  // Our mission, should we choose to accept it, is to scan through the 2D hits and reject
754  // any outliers. Basically, any hit outside a scaled range of the average doca from the
755  // first pass is marked by setting the bit in the status word.
756 
757  // First get the average doca scaled by some appropriate factor
758  int numRejHits(0);
759 
760  // Outer loop over views
761  for (const auto& hit3D : hitPairVector)
762  {
763  // Inner loop over hits in this view
764  for (const auto& hit : hit3D->getHits())
765  {
766  // Always reset the existing status bit
767  hit->clearStatusBits(0x80);
768 
769  if (hit->getDocaToAxis() > maxDocaAllowed)
770  {
771  hit->setStatusBit(0x80);
772  numRejHits++;
773  }
774  }
775  }
776 
777  return numRejHits;
778 }
Detector simulation of raw signals on wires.
int lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_reject3DOutliers ( const reco::HitPairListPtr hitPairVector,
const reco::PrincipalComponents pca,
float  aveHitDoca 
) const

Definition at line 667 of file PrincipalComponentsAlg.cxx.

670  {
671  // Our mission, should we choose to accept it, is to scan through the 2D hits and reject
672  // any outliers. Basically, any hit outside a scaled range of the average doca from the
673  // first pass is marked by setting the bit in the status word.
674 
675  // First get the average doca scaled by some appropriate factor
676  int numRejHits(0);
677 
678  // We'll need the current PCA axis to determine doca and arclen
679  Eigen::Vector3f avePosition(
680  pca.getAvePosition()[0], pca.getAvePosition()[1], pca.getAvePosition()[2]);
681  Eigen::Vector3f axisDirVec(pca.getEigenVectors().row(2));
682 
683  // Outer loop over views
684  for (const auto* clusterHit3D : hitPairVector) {
685  // Always reset the existing status bit
686  clusterHit3D->clearStatusBits(0x80);
687 
688  // Now we need to calculate the doca and poca...
689  // Start by getting this hits position
690  Eigen::Vector3f clusPos(clusterHit3D->getPosition()[0],
691  clusterHit3D->getPosition()[1],
692  clusterHit3D->getPosition()[2]);
693 
694  // Form a TVector from this to the cluster average position
695  Eigen::Vector3f clusToHitVec = clusPos - avePosition;
696 
697  // With this we can get the arclength to the doca point
698  float arclenToPoca = clusToHitVec.dot(axisDirVec);
699 
700  // Get the coordinates along the axis for this point
701  Eigen::Vector3f docaPos = avePosition + arclenToPoca * axisDirVec;
702 
703  // Now get doca and poca
704  Eigen::Vector3f docaPosToClusPos = clusPos - docaPos;
705  float docaToAxis = docaPosToClusPos.norm();
706 
707  // Ok, set the values in the hit
708  clusterHit3D->setDocaToAxis(docaToAxis);
709  clusterHit3D->setArclenToPoca(arclenToPoca);
710 
711  // Check to see if this is a keeper
712  if (clusterHit3D->getDocaToAxis() > maxDocaAllowed) {
713  clusterHit3D->setStatusBit(0x80);
714  numRejHits++;
715  }
716  }
717 
718  return numRejHits;
719  }
const Eigen::Vector3f & getAvePosition() const
Definition: Cluster3D.h:248
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
int lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_reject3DOutliers ( const reco::HitPairListPtr hitPairVector,
const reco::PrincipalComponents pca,
double  aveHitDoca 
) const

Definition at line 780 of file PrincipalComponentsAlg.cxx.

783 {
784  // Our mission, should we choose to accept it, is to scan through the 2D hits and reject
785  // any outliers. Basically, any hit outside a scaled range of the average doca from the
786  // first pass is marked by setting the bit in the status word.
787 
788  // First get the average doca scaled by some appropriate factor
789  int numRejHits(0);
790 
791  // We'll need the current PCA axis to determine doca and arclen
792  TVector3 avePosition(pca.getAvePosition()[0], pca.getAvePosition()[1], pca.getAvePosition()[2]);
793  TVector3 axisDirVec(pca.getEigenVectors()[0][0], pca.getEigenVectors()[0][1], pca.getEigenVectors()[0][2]);
794 
795  // Outer loop over views
796  for (const auto* clusterHit3D : hitPairVector)
797  {
798  // Always reset the existing status bit
799  clusterHit3D->clearStatusBits(0x80);
800 
801  // Now we need to calculate the doca and poca...
802  // Start by getting this hits position
803  TVector3 clusPos(clusterHit3D->getPosition()[0],clusterHit3D->getPosition()[1],clusterHit3D->getPosition()[2]);
804 
805  // Form a TVector from this to the cluster average position
806  TVector3 clusToHitVec = clusPos - avePosition;
807 
808  // With this we can get the arclength to the doca point
809  double arclenToPoca = clusToHitVec.Dot(axisDirVec);
810 
811  // Get the coordinates along the axis for this point
812  TVector3 docaPos = avePosition + arclenToPoca * axisDirVec;
813 
814  // Now get doca and poca
815  TVector3 docaPosToClusPos = clusPos - docaPos;
816  double docaToAxis = docaPosToClusPos.Mag();
817 
818  // Ok, set the values in the hit
819  clusterHit3D->setDocaToAxis(docaToAxis);
820  clusterHit3D->setArclenToPoca(arclenToPoca);
821 
822  // Check to see if this is a keeper
823  if (clusterHit3D->getDocaToAxis() > maxDocaAllowed)
824  {
825  clusterHit3D->setStatusBit(0x80);
826  numRejHits++;
827  }
828  }
829 
830  return numRejHits;
831 }
const Eigen::Vector3f & getAvePosition() const
Definition: Cluster3D.h:248
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247
void lar_cluster3d::PrincipalComponentsAlg::reconfigure ( fhicl::ParameterSet const &  pset)

a handler for the case where the algorithm control parameters are to be reset

Definition at line 52 of file PrincipalComponentsAlg.cxx.

53 {
55 
56  m_parallel = pset.get<double>("ParallelLines", 0.00001);
57  m_geometry = &*geometry;
58 }
double m_parallel
means lines are parallel

Member Data Documentation

const detinfo::DetectorProperties* lar_cluster3d::PrincipalComponentsAlg::m_detector
private

Definition at line 91 of file PrincipalComponentsAlg.h.

const geo::Geometry* lar_cluster3d::PrincipalComponentsAlg::m_geometry
private

Definition at line 75 of file PrincipalComponentsAlg.h.

geo::Geometry* lar_cluster3d::PrincipalComponentsAlg::m_geometry
private

Definition at line 90 of file PrincipalComponentsAlg.h.

float lar_cluster3d::PrincipalComponentsAlg::m_parallel
private

means lines are parallel

Definition at line 74 of file PrincipalComponentsAlg.h.

double lar_cluster3d::PrincipalComponentsAlg::m_parallel
private

means lines are parallel

Definition at line 88 of file PrincipalComponentsAlg.h.


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