LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
lar_cluster3d::PCASeedFinderAlg Class Reference

PCASeedFinderAlg class. More...

#include "PCASeedFinderAlg.h"

Inheritance diagram for lar_cluster3d::PCASeedFinderAlg:
lar_cluster3d::SeedFinderAlgBase

Public Member Functions

 PCASeedFinderAlg (fhicl::ParameterSet const &pset)
 Constructor. More...
 
virtual ~PCASeedFinderAlg ()
 Destructor. More...
 
virtual void reconfigure (fhicl::ParameterSet const &pset)
 a handler for the case where the algorithm control parameters are to be reset More...
 
virtual bool findTrackSeeds (reco::HitPairListPtr &hitPairListPtr, reco::PrincipalComponents &inputPCA, SeedHitPairListPairVec &seedHitMap) const
 Given the list of hits this will search for candidate Seed objects and return them. More...
 

Private Member Functions

bool getHitsAtEnd (reco::HitPairListPtr &hit3DList, reco::PrincipalComponents &seedPca) const
 Separate function to find hits at the ends of the input hits. More...
 
void LineFit2DHits (const reco::HitPairListPtr &hitList, double XOrigin, TVector3 &Pos, TVector3 &Dir, double &ChiDOF) const
 

Private Attributes

geo::Geometrym_geometry
 
double m_gapDistance
 
size_t m_numSeed2DHits
 
double m_minAllowedCosAng
 The minimum cos(ang) between input and seed axes. More...
 
PrincipalComponentsAlg m_pcaAlg
 

Detailed Description

PCASeedFinderAlg class.

Definition at line 36 of file PCASeedFinderAlg.h.

Constructor & Destructor Documentation

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

Constructor.

Parameters
pset

Definition at line 43 of file PCASeedFinderAlg.cxx.

References m_geometry, and reconfigure().

43  :
44  m_gapDistance(5.),
45  m_numSeed2DHits(80),
46  m_minAllowedCosAng(0.7),
47  m_pcaAlg(pset.get<fhicl::ParameterSet>("PrincipalComponentsAlg"))
48 {
49  this->reconfigure(pset);
50 
52  // auto const* detectorProperties = lar::providerFrom<detinfo::DetectorPropertiesService>();
53 
54  m_geometry = &*geometry;
55  // m_detector = detectorProperties->provider();
56 }
PrincipalComponentsAlg m_pcaAlg
virtual void reconfigure(fhicl::ParameterSet const &pset)
a handler for the case where the algorithm control parameters are to be reset
double m_minAllowedCosAng
The minimum cos(ang) between input and seed axes.
lar_cluster3d::PCASeedFinderAlg::~PCASeedFinderAlg ( )
virtual

Destructor.

Definition at line 60 of file PCASeedFinderAlg.cxx.

61 {
62 }

Member Function Documentation

bool lar_cluster3d::PCASeedFinderAlg::findTrackSeeds ( reco::HitPairListPtr hitPairListPtr,
reco::PrincipalComponents inputPCA,
SeedHitPairListPairVec seedHitMap 
) const
virtual

Given the list of hits this will search for candidate Seed objects and return them.

Implements lar_cluster3d::SeedFinderAlgBase.

Definition at line 72 of file PCASeedFinderAlg.cxx.

References reco::PrincipalComponents::flipAxis(), reco::PrincipalComponents::getEigenValues(), reco::PrincipalComponents::getEigenVectors(), getHitsAtEnd(), LineFit2DHits(), m_pcaAlg, and lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_calc3DDocas().

Referenced by lar_cluster3d::Cluster3D::findTrackSeeds().

75 {
76  bool foundGoodSeed(false);
77 
78  // Make sure we are using the right pca
79  reco::HitPairListPtr hitPairListPtr = inputHitPairListPtr;
80 
81  // Make a local copy of the input pca
82  reco::PrincipalComponents pca = inputPCA;
83 
84  // We also require that there be some spread in the data, otherwise not worth running?
85  double eigenVal0 = 3. * sqrt(pca.getEigenValues()[0]);
86  double eigenVal1 = 3. * sqrt(pca.getEigenValues()[1]);
87 
88  if (eigenVal0 > 5. && eigenVal1 > 0.001)
89  {
90  // Presume CR muons will be "downward going"...
91  if (pca.getEigenVectors()[0][1] > 0.) pca.flipAxis(0);
92 
93  // Use the following to set the 3D doca and arclength for each hit
94  m_pcaAlg.PCAAnalysis_calc3DDocas(hitPairListPtr, pca);
95 
96  // Use this info to sort the hits along the principle axis
97  hitPairListPtr.sort(SeedFinderAlgBase::Sort3DHitsByArcLen3D());
98  //hitPairListPtr.sort(PcaSort3DHitsByAbsArcLen3D());
99 
100  // Make a local copy of the 3D hits
101  reco::HitPairListPtr hit3DList;
102 
103  hit3DList.resize(hitPairListPtr.size());
104 
105  std::copy(hitPairListPtr.begin(), hitPairListPtr.end(), hit3DList.begin());
106 
107  reco::PrincipalComponents seedPca = pca;
108 
109  if (getHitsAtEnd(hit3DList, seedPca))
110  {
111  // We can use the same routine to check hits at the opposite end to make sure
112  // we have consistency between both ends of the track.
113  // So... follow the same general program as above
114  reco::HitPairListPtr checkList;
115 
116  checkList.resize(hitPairListPtr.size());
117 
118  std::copy(hitPairListPtr.begin(), hitPairListPtr.end(), checkList.begin());
119 
120  std::reverse(checkList.begin(), checkList.end());
121 
122  reco::PrincipalComponents checkPca = pca;
123 
124  if (getHitsAtEnd(checkList, checkPca))
125  {
126  // We want our seed to be in the middle of our seed points
127  // First step to getting there is to reorder the hits along the
128  // new pca axis
129  m_pcaAlg.PCAAnalysis_calc3DDocas(hit3DList, seedPca);
130 
131  // Use this info to sort the hits along the principle axis - note by absolute value of arc length
132  hit3DList.sort(SeedFinderAlgBase::Sort3DHitsByAbsArcLen3D());
133 
134  // Now translate the seedCenter by the arc len to the first hit
135  double seedDir[3] = {seedPca.getEigenVectors()[0][0], seedPca.getEigenVectors()[0][1], seedPca.getEigenVectors()[0][2]};
136  double seedStart[3] = {hit3DList.front()->getX(), hit3DList.front()->getY(), hit3DList.front()->getZ()};
137 
138  if (hit3DList.size() > 10)
139  {
140  TVector3 newSeedPos;
141  TVector3 newSeedDir;
142  double chiDOF;
143 
144  LineFit2DHits(hit3DList, seedStart[0], newSeedPos, newSeedDir, chiDOF);
145 
146  if (chiDOF > 0.)
147  {
148  // check angles between new/old directions
149  double cosAng = seedDir[0]*newSeedDir[0]+seedDir[1]*newSeedDir[1]+seedDir[2]*newSeedDir[2];
150 
151  if (cosAng < 0.) newSeedDir *= -1.;
152 
153  seedStart[0] = newSeedPos[0];
154  seedStart[1] = newSeedPos[1];
155  seedStart[2] = newSeedPos[2];
156  seedDir[0] = newSeedDir[0];
157  seedDir[1] = newSeedDir[1];
158  seedDir[2] = newSeedDir[2];
159  }
160  }
161 
162  for(const auto& hit3D : hit3DList) hit3D->setStatusBit(0x40000000);
163 
164  seedHitPairVec.emplace_back(std::pair<recob::Seed, reco::HitPairListPtr>(recob::Seed(seedStart, seedDir), hit3DList));
165 
166  foundGoodSeed = true;
167  }
168  }
169  }
170 
171  return foundGoodSeed;
172 }
void PCAAnalysis_calc3DDocas(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca) const
bool getHitsAtEnd(reco::HitPairListPtr &hit3DList, reco::PrincipalComponents &seedPca) const
Separate function to find hits at the ends of the input hits.
void flipAxis(size_t axis)
Definition: Cluster3D.cxx:195
PrincipalComponentsAlg m_pcaAlg
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:315
const float * getEigenValues() const
Definition: Cluster3D.h:226
void LineFit2DHits(const reco::HitPairListPtr &hitList, double XOrigin, TVector3 &Pos, TVector3 &Dir, double &ChiDOF) const
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:227
bool lar_cluster3d::PCASeedFinderAlg::getHitsAtEnd ( reco::HitPairListPtr hit3DList,
reco::PrincipalComponents seedPca 
) const
private

Separate function to find hits at the ends of the input hits.

Definition at line 174 of file PCASeedFinderAlg.cxx.

References reco::PrincipalComponents::flipAxis(), reco::ClusterHit3D::getArclenToPoca(), reco::PrincipalComponents::getEigenVectors(), reco::ClusterHit3D::getHits(), reco::PrincipalComponents::getSvdOK(), m_gapDistance, m_minAllowedCosAng, m_numSeed2DHits, m_pcaAlg, and lar_cluster3d::PrincipalComponentsAlg::PCAAnalysis_3D().

Referenced by findTrackSeeds().

175 {
176  bool foundGoodSeedHits(false);
177 
178  // Use a set to count 2D hits by keeping only a single copy
179  std::set<const reco::ClusterHit2D*> hit2DSet;
180 
181  // Look for numSeed2DHits which are continuous
182  double lastArcLen = hit3DList.front()->getArclenToPoca();
183 
184  reco::HitPairListPtr::iterator startItr = hit3DList.begin();
185  reco::HitPairListPtr::iterator lastItr = hit3DList.begin();
186 
187  while(++lastItr != hit3DList.end())
188  {
189  const reco::ClusterHit3D* hit3D = *lastItr;
190  double arcLen = hit3D->getArclenToPoca();
191 
192  if (fabs(arcLen-lastArcLen) > m_gapDistance)
193  {
194  startItr = lastItr;
195  hit2DSet.clear();
196  }
197 
198  for(const auto& hit2D : hit3D->getHits())
199  {
200  hit2DSet.insert(hit2D);
201  }
202 
203  if (hit2DSet.size() > m_numSeed2DHits) break;
204 
205  lastArcLen = arcLen;
206  }
207 
208  if (hit2DSet.size() > m_numSeed2DHits)
209  {
210  if (startItr != hit3DList.begin()) hit3DList.erase(hit3DList.begin(), startItr);
211  if (lastItr != hit3DList.end() ) hit3DList.erase(lastItr, hit3DList.end());
212 
213  // On input, the seedPca will contain the original values so we can recover the original axis now
214  TVector3 planeVec0(seedPca.getEigenVectors()[0][0],seedPca.getEigenVectors()[0][1],seedPca.getEigenVectors()[0][2]);
215 
216  m_pcaAlg.PCAAnalysis_3D(hit3DList, seedPca, true);
217 
218  if (seedPca.getSvdOK())
219  {
220  // Still looking to point "down"
221  if (seedPca.getEigenVectors()[0][1] > 0.) seedPca.flipAxis(0);
222 
223  // Check that the seed PCA we have found is consistent with the input PCA
224  TVector3 primarySeedAxis(seedPca.getEigenVectors()[0][0],seedPca.getEigenVectors()[0][1],seedPca.getEigenVectors()[0][2]);
225 
226  double cosAng = primarySeedAxis.Dot(planeVec0);
227 
228  // If the proposed seed axis is not relatively aligned with the input PCA then
229  // we should not be using this method to return seeds. Check that here
230  if (cosAng > m_minAllowedCosAng) foundGoodSeedHits = true;
231  }
232  }
233 
234  return foundGoodSeedHits;
235 }
bool getSvdOK() const
Definition: Cluster3D.h:224
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
void flipAxis(size_t axis)
Definition: Cluster3D.cxx:195
intermediate_table::iterator iterator
PrincipalComponentsAlg m_pcaAlg
double m_minAllowedCosAng
The minimum cos(ang) between input and seed axes.
float getArclenToPoca() const
Definition: Cluster3D.h:155
const ClusterHit2DVec & getHits() const
Definition: Cluster3D.h:156
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:227
void lar_cluster3d::PCASeedFinderAlg::LineFit2DHits ( const reco::HitPairListPtr hitList,
double  XOrigin,
TVector3 &  Pos,
TVector3 &  Dir,
double &  ChiDOF 
) const
private

Definition at line 238 of file PCASeedFinderAlg.cxx.

References geo::CryostatID::Cryostat, m_geometry, norm, geo::PlaneID::Plane, sw, geo::TPCID::TPC, w, geo::WireID::Wire, geo::GeometryCore::WireCoordinate(), geo::GeometryCore::WirePitch(), and x.

Referenced by findTrackSeeds().

243 {
244  // The following is lifted from Bruce Baller to try to get better
245  // initial parameters for a candidate Seed. It is slightly reworked
246  // which is why it is included here instead of used as is.
247  //
248  // Linear fit using X as the independent variable. Hits to be fitted
249  // are passed in the hits vector in a pair form (X, WireID). The
250  // fitted track position at XOrigin is returned in the Pos vector.
251  // The direction cosines are returned in the Dir vector.
252  //
253  // SVD fit adapted from $ROOTSYS/tutorials/matrix/solveLinear.C
254  // Fit equation is w = A(X)v, where w is a vector of hit wires, A is
255  // a matrix to calculate a track projected to a point at X, and v is
256  // a vector (Yo, Zo, dY/dX, dZ/dX).
257  //
258  // Note: The covariance matrix should also be returned
259  // B. Baller August 2014
260 
261  // assume failure
262  ChiDOF = -1;
263 
264  // Make a set of 2D hits so we consider only unique hits
265  std::set<const reco::ClusterHit2D*> hit2DSet;
266 
267  for(const auto& hit3D : hit3DList)
268  {
269  for(const auto& hit2D : hit3D->getHits()) hit2DSet.insert(hit2D);
270  }
271 
272  if(hit2DSet.size() < 4) return;
273 
274  const unsigned int nvars = 4;
275  unsigned int npts = 3 * hit3DList.size();
276 
277  TMatrixD A(npts, nvars);
278  // vector holding the Wire number
279  TVectorD w(npts);
280  unsigned short ninpl[3] = {0};
281  unsigned short nok = 0;
282  unsigned short iht(0), cstat, tpc, ipl;
283  double x, cw, sw, off;
284 
285  // Loop over the 2D hits in the above
286  for (const auto& hit : hit2DSet)
287  {
288  geo::WireID wireID = hit->getHit().WireID();
289 
290  cstat = wireID.Cryostat;
291  tpc = wireID.TPC;
292  ipl = wireID.Plane;
293 
294  // get the wire plane offset
295  off = m_geometry->WireCoordinate(0, 0, ipl, tpc, cstat);
296 
297  // get the "cosine-like" component
298  cw = m_geometry->WireCoordinate(1, 0, ipl, tpc, cstat) - off;
299 
300  // the "sine-like" component
301  sw = m_geometry->WireCoordinate(0, 1, ipl, tpc, cstat) - off;
302 
303  x = hit->getXPosition() - XOrigin;
304 
305  A[iht][0] = cw;
306  A[iht][1] = sw;
307  A[iht][2] = cw * x;
308  A[iht][3] = sw * x;
309  w[iht] = wireID.Wire - off;
310 
311  ++ninpl[ipl];
312 
313  // need at least two points in a plane
314  if(ninpl[ipl] == 2) ++nok;
315 
316  iht++;
317  }
318 
319  // need at least 2 planes with at least two points
320  if(nok < 2) return;
321 
322  TDecompSVD svd(A);
323  bool ok;
324  TVectorD tVec = svd.Solve(w, ok);
325 
326  ChiDOF = 0;
327 
328  // not enough points to calculate Chisq
329  if(npts <= 4) return;
330 
331  double ypr, zpr, diff;
332 
333  for (const auto& hit : hit2DSet)
334  {
335  geo::WireID wireID = hit->getHit().WireID();
336 
337  cstat = wireID.Cryostat;
338  tpc = wireID.TPC;
339  ipl = wireID.Plane;
340  off = m_geometry->WireCoordinate(0, 0, ipl, tpc, cstat);
341  cw = m_geometry->WireCoordinate(1, 0, ipl, tpc, cstat) - off;
342  sw = m_geometry->WireCoordinate(0, 1, ipl, tpc, cstat) - off;
343  x = hit->getXPosition() - XOrigin;
344  ypr = tVec[0] + tVec[2] * x;
345  zpr = tVec[1] + tVec[3] * x;
346  diff = ypr * cw + zpr * sw - (wireID.Wire - off);
347  ChiDOF += diff * diff;
348  }
349 
350  float werr2 = m_geometry->WirePitch() * m_geometry->WirePitch();
351  ChiDOF /= werr2;
352  ChiDOF /= (float)(npts - 4);
353 
354  double norm = sqrt(1 + tVec[2] * tVec[2] + tVec[3] * tVec[3]);
355  Dir[0] = 1 / norm;
356  Dir[1] = tVec[2] / norm;
357  Dir[2] = tVec[3] / norm;
358 
359  Pos[0] = XOrigin;
360  Pos[1] = tVec[0];
361  Pos[2] = tVec[1];
362 
363 } // TrkLineFit()
Float_t x
Definition: compare.C:6
geo::Length_t WireCoordinate(double YPos, double ZPos, geo::PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:130
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:258
Detector simulation of raw signals on wires.
Float_t sw
Definition: plot.C:23
Float_t norm
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
Float_t w
Definition: plot.C:23
void lar_cluster3d::PCASeedFinderAlg::reconfigure ( fhicl::ParameterSet const &  pset)
virtual

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

Implements lar_cluster3d::SeedFinderAlgBase.

Definition at line 64 of file PCASeedFinderAlg.cxx.

References fhicl::ParameterSet::get(), m_gapDistance, m_minAllowedCosAng, m_numSeed2DHits, m_pcaAlg, and lar_cluster3d::PrincipalComponentsAlg::reconfigure().

Referenced by PCASeedFinderAlg(), and lar_cluster3d::Cluster3D::reconfigure().

65 {
66  m_gapDistance = pset.get<double>("GapDistance", 5.);
67  m_numSeed2DHits = pset.get<size_t>("NumSeed2DHits", 80);
68  m_minAllowedCosAng = pset.get<double>("MinAllowedCosAng", 0.7);
69  m_pcaAlg.reconfigure(pset.get<fhicl::ParameterSet>("PrincipalComponentsAlg"));
70 }
void reconfigure(fhicl::ParameterSet const &pset)
a handler for the case where the algorithm control parameters are to be reset
PrincipalComponentsAlg m_pcaAlg
double m_minAllowedCosAng
The minimum cos(ang) between input and seed axes.

Member Data Documentation

double lar_cluster3d::PCASeedFinderAlg::m_gapDistance
private

Definition at line 75 of file PCASeedFinderAlg.h.

Referenced by getHitsAtEnd(), and reconfigure().

geo::Geometry* lar_cluster3d::PCASeedFinderAlg::m_geometry
private

Definition at line 72 of file PCASeedFinderAlg.h.

Referenced by LineFit2DHits(), and PCASeedFinderAlg().

double lar_cluster3d::PCASeedFinderAlg::m_minAllowedCosAng
private

The minimum cos(ang) between input and seed axes.

Definition at line 77 of file PCASeedFinderAlg.h.

Referenced by getHitsAtEnd(), and reconfigure().

size_t lar_cluster3d::PCASeedFinderAlg::m_numSeed2DHits
private

Definition at line 76 of file PCASeedFinderAlg.h.

Referenced by getHitsAtEnd(), and reconfigure().

PrincipalComponentsAlg lar_cluster3d::PCASeedFinderAlg::m_pcaAlg
private

Definition at line 79 of file PCASeedFinderAlg.h.

Referenced by findTrackSeeds(), getHitsAtEnd(), and reconfigure().


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