All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Public Member Functions | Private Member Functions | Private Attributes | List of all members
lar_cluster3d::PCASeedFinderAlg Class Referencefinal

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...
 
bool findTrackSeeds (reco::HitPairListPtr &hitPairListPtr, reco::PrincipalComponents &inputPCA, SeedHitPairListPairVec &seedHitMap) const override
 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::Geometry const * m_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 31 of file PCASeedFinderAlg.h.

Constructor & Destructor Documentation

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

Constructor.

Parameters
pset

Definition at line 36 of file PCASeedFinderAlg.cxx.

37  : m_gapDistance(5.)
38  , m_numSeed2DHits(80)
39  , m_minAllowedCosAng(0.7)
40  , m_pcaAlg(pset.get<fhicl::ParameterSet>("PrincipalComponentsAlg"))
41  {
42  m_gapDistance = pset.get<double>("GapDistance", 5.);
43  m_numSeed2DHits = pset.get<size_t>("NumSeed2DHits", 80);
44  m_minAllowedCosAng = pset.get<double>("MinAllowedCosAng", 0.7);
45  m_geometry = art::ServiceHandle<geo::Geometry const>{}.get();
46  }
geo::Geometry const * m_geometry
PrincipalComponentsAlg m_pcaAlg
double m_minAllowedCosAng
The minimum cos(ang) between input and seed axes.

Member Function Documentation

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

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

Implements lar_cluster3d::SeedFinderAlgBase.

Definition at line 49 of file PCASeedFinderAlg.cxx.

52  {
53  bool foundGoodSeed(false);
54 
55  // Make sure we are using the right pca
56  reco::HitPairListPtr hitPairListPtr = inputHitPairListPtr;
57 
58  // Make a local copy of the input pca
59  reco::PrincipalComponents pca = inputPCA;
60 
61  // We also require that there be some spread in the data, otherwise not worth running?
62  double eigenVal0 = 3. * sqrt(pca.getEigenValues()[2]);
63  double eigenVal1 = 3. * sqrt(pca.getEigenValues()[1]);
64 
65  if (eigenVal0 > 5. && eigenVal1 > 0.001) {
66  // Presume CR muons will be "downward going"...
67  if (pca.getEigenVectors().row(2)(1) > 0.) pca.flipAxis(0);
68 
69  // Use the following to set the 3D doca and arclength for each hit
70  m_pcaAlg.PCAAnalysis_calc3DDocas(hitPairListPtr, pca);
71 
72  // Use this info to sort the hits along the principle axis
73  hitPairListPtr.sort(SeedFinderAlgBase::Sort3DHitsByArcLen3D());
74  //hitPairListPtr.sort(PcaSort3DHitsByAbsArcLen3D());
75 
76  // Make a local copy of the 3D hits
77  reco::HitPairListPtr hit3DList;
78 
79  hit3DList.resize(hitPairListPtr.size());
80 
81  std::copy(hitPairListPtr.begin(), hitPairListPtr.end(), hit3DList.begin());
82 
83  reco::PrincipalComponents seedPca = pca;
84 
85  if (getHitsAtEnd(hit3DList, seedPca)) {
86  // We can use the same routine to check hits at the opposite end to make sure
87  // we have consistency between both ends of the track.
88  // So... follow the same general program as above
89  reco::HitPairListPtr checkList;
90 
91  checkList.resize(hitPairListPtr.size());
92 
93  std::copy(hitPairListPtr.begin(), hitPairListPtr.end(), checkList.begin());
94 
95  std::reverse(checkList.begin(), checkList.end());
96 
97  reco::PrincipalComponents checkPca = pca;
98 
99  if (getHitsAtEnd(checkList, checkPca)) {
100  // We want our seed to be in the middle of our seed points
101  // First step to getting there is to reorder the hits along the
102  // new pca axis
103  m_pcaAlg.PCAAnalysis_calc3DDocas(hit3DList, seedPca);
104 
105  // Use this info to sort the hits along the principle axis - note by absolute value of arc length
106  hit3DList.sort(SeedFinderAlgBase::Sort3DHitsByAbsArcLen3D());
107 
108  // Now translate the seedCenter by the arc len to the first hit
109  double seedDir[3] = {seedPca.getEigenVectors().row(2)(0),
110  seedPca.getEigenVectors().row(2)(1),
111  seedPca.getEigenVectors().row(2)(2)};
112  double seedStart[3] = {
113  hit3DList.front()->getX(), hit3DList.front()->getY(), hit3DList.front()->getZ()};
114 
115  if (hit3DList.size() > 10) {
116  TVector3 newSeedPos;
117  TVector3 newSeedDir;
118  double chiDOF;
119 
120  LineFit2DHits(hit3DList, seedStart[0], newSeedPos, newSeedDir, chiDOF);
121 
122  if (chiDOF > 0.) {
123  // check angles between new/old directions
124  double cosAng = seedDir[0] * newSeedDir[0] + seedDir[1] * newSeedDir[1] +
125  seedDir[2] * newSeedDir[2];
126 
127  if (cosAng < 0.) newSeedDir *= -1.;
128 
129  seedStart[0] = newSeedPos[0];
130  seedStart[1] = newSeedPos[1];
131  seedStart[2] = newSeedPos[2];
132  seedDir[0] = newSeedDir[0];
133  seedDir[1] = newSeedDir[1];
134  seedDir[2] = newSeedDir[2];
135  }
136  }
137 
138  for (const auto& hit3D : hit3DList)
139  hit3D->setStatusBit(0x40000000);
140 
141  seedHitPairVec.emplace_back(std::pair<recob::Seed, reco::HitPairListPtr>(
142  recob::Seed(seedStart, seedDir), hit3DList));
143 
144  foundGoodSeed = true;
145  }
146  }
147  }
148 
149  return foundGoodSeed;
150  }
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:208
PrincipalComponentsAlg m_pcaAlg
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:245
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:334
T copy(T const &v)
void LineFit2DHits(const reco::HitPairListPtr &hitList, double XOrigin, TVector3 &Pos, TVector3 &Dir, double &ChiDOF) const
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:246
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 153 of file PCASeedFinderAlg.cxx.

155  {
156  bool foundGoodSeedHits(false);
157 
158  // Use a set to count 2D hits by keeping only a single copy
159  std::set<const reco::ClusterHit2D*> hit2DSet;
160 
161  // Look for numSeed2DHits which are continuous
162  double lastArcLen = hit3DList.front()->getArclenToPoca();
163 
164  reco::HitPairListPtr::iterator startItr = hit3DList.begin();
165  reco::HitPairListPtr::iterator lastItr = hit3DList.begin();
166 
167  while (++lastItr != hit3DList.end()) {
168  const reco::ClusterHit3D* hit3D = *lastItr;
169  double arcLen = hit3D->getArclenToPoca();
170 
171  if (fabs(arcLen - lastArcLen) > m_gapDistance) {
172  startItr = lastItr;
173  hit2DSet.clear();
174  }
175 
176  for (const auto& hit2D : hit3D->getHits()) {
177  hit2DSet.insert(hit2D);
178  }
179 
180  if (hit2DSet.size() > m_numSeed2DHits) break;
181 
182  lastArcLen = arcLen;
183  }
184 
185  if (hit2DSet.size() > m_numSeed2DHits) {
186  if (startItr != hit3DList.begin()) hit3DList.erase(hit3DList.begin(), startItr);
187  if (lastItr != hit3DList.end()) hit3DList.erase(lastItr, hit3DList.end());
188 
189  // On input, the seedPca will contain the original values so we can recover the original axis now
190  Eigen::Vector3f planeVec0(seedPca.getEigenVectors().row(2));
191 
192  m_pcaAlg.PCAAnalysis_3D(hit3DList, seedPca, true);
193 
194  if (seedPca.getSvdOK()) {
195  // Still looking to point "down"
196  if (seedPca.getEigenVectors().row(2)(1) > 0.) seedPca.flipAxis(0);
197 
198  // Check that the seed PCA we have found is consistent with the input PCA
199  Eigen::Vector3f primarySeedAxis(seedPca.getEigenVectors().row(2));
200 
201  double cosAng = primarySeedAxis.dot(planeVec0);
202 
203  // If the proposed seed axis is not relatively aligned with the input PCA then
204  // we should not be using this method to return seeds. Check that here
205  if (cosAng > m_minAllowedCosAng) foundGoodSeedHits = true;
206  }
207  }
208 
209  return foundGoodSeedHits;
210  }
bool getSvdOK() const
Definition: Cluster3D.h:243
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
void flipAxis(size_t axis)
Definition: Cluster3D.cxx:208
PrincipalComponentsAlg m_pcaAlg
double m_minAllowedCosAng
The minimum cos(ang) between input and seed axes.
float getArclenToPoca() const
Definition: Cluster3D.h:169
const ClusterHit2DVec & getHits() const
Definition: Cluster3D.h:170
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:246
void lar_cluster3d::PCASeedFinderAlg::LineFit2DHits ( const reco::HitPairListPtr hitList,
double  XOrigin,
TVector3 &  Pos,
TVector3 &  Dir,
double &  ChiDOF 
) const
private

Definition at line 214 of file PCASeedFinderAlg.cxx.

219  {
220  // The following is lifted from Bruce Baller to try to get better
221  // initial parameters for a candidate Seed. It is slightly reworked
222  // which is why it is included here instead of used as is.
223  //
224  // Linear fit using X as the independent variable. Hits to be fitted
225  // are passed in the hits vector in a pair form (X, WireID). The
226  // fitted track position at XOrigin is returned in the Pos vector.
227  // The direction cosines are returned in the Dir vector.
228  //
229  // SVD fit adapted from $ROOTSYS/tutorials/matrix/solveLinear.C
230  // Fit equation is w = A(X)v, where w is a vector of hit wires, A is
231  // a matrix to calculate a track projected to a point at X, and v is
232  // a vector (Yo, Zo, dY/dX, dZ/dX).
233  //
234  // Note: The covariance matrix should also be returned
235  // B. Baller August 2014
236 
237  // assume failure
238  ChiDOF = -1;
239 
240  // Make a set of 2D hits so we consider only unique hits
241  std::set<const reco::ClusterHit2D*> hit2DSet;
242 
243  for (const auto& hit3D : hit3DList) {
244  for (const auto& hit2D : hit3D->getHits())
245  hit2DSet.insert(hit2D);
246  }
247 
248  if (hit2DSet.size() < 4) return;
249 
250  const unsigned int nvars = 4;
251  unsigned int npts = 3 * hit3DList.size();
252 
253  TMatrixD A(npts, nvars);
254  // vector holding the Wire number
255  TVectorD w(npts);
256  unsigned short ninpl[3] = {0};
257  unsigned short nok = 0;
258  unsigned short iht(0), cstat, tpc, ipl;
259  double x, cw, sw, off;
260 
261  // Loop over the 2D hits in the above
262  for (const auto& hit : hit2DSet) {
263  geo::WireID wireID = hit->WireID();
264 
265  cstat = wireID.Cryostat;
266  tpc = wireID.TPC;
267  ipl = wireID.Plane;
268 
269  // get the wire plane offset
270  off = m_geometry->WireCoordinate(0, 0, ipl, tpc, cstat);
271 
272  // get the "cosine-like" component
273  cw = m_geometry->WireCoordinate(1, 0, ipl, tpc, cstat) - off;
274 
275  // the "sine-like" component
276  sw = m_geometry->WireCoordinate(0, 1, ipl, tpc, cstat) - off;
277 
278  x = hit->getXPosition() - XOrigin;
279 
280  A[iht][0] = cw;
281  A[iht][1] = sw;
282  A[iht][2] = cw * x;
283  A[iht][3] = sw * x;
284  w[iht] = wireID.Wire - off;
285 
286  ++ninpl[ipl];
287 
288  // need at least two points in a plane
289  if (ninpl[ipl] == 2) ++nok;
290 
291  iht++;
292  }
293 
294  // need at least 2 planes with at least two points
295  if (nok < 2) return;
296 
297  TDecompSVD svd(A);
298  bool ok;
299  TVectorD tVec = svd.Solve(w, ok);
300 
301  ChiDOF = 0;
302 
303  // not enough points to calculate Chisq
304  if (npts <= 4) return;
305 
306  double ypr, zpr, diff;
307 
308  for (const auto& hit : hit2DSet) {
309  geo::WireID wireID = hit->WireID();
310 
311  cstat = wireID.Cryostat;
312  tpc = wireID.TPC;
313  ipl = wireID.Plane;
314  off = m_geometry->WireCoordinate(0, 0, ipl, tpc, cstat);
315  cw = m_geometry->WireCoordinate(1, 0, ipl, tpc, cstat) - off;
316  sw = m_geometry->WireCoordinate(0, 1, ipl, tpc, cstat) - off;
317  x = hit->getXPosition() - XOrigin;
318  ypr = tVec[0] + tVec[2] * x;
319  zpr = tVec[1] + tVec[3] * x;
320  diff = ypr * cw + zpr * sw - (wireID.Wire - off);
321  ChiDOF += diff * diff;
322  }
323 
324  float werr2 = m_geometry->WirePitch() * m_geometry->WirePitch();
325  ChiDOF /= werr2;
326  ChiDOF /= (float)(npts - 4);
327 
328  double norm = sqrt(1 + tVec[2] * tVec[2] + tVec[3] * tVec[3]);
329  Dir[0] = 1 / norm;
330  Dir[1] = tVec[2] / norm;
331  Dir[2] = tVec[3] / norm;
332 
333  Pos[0] = XOrigin;
334  Pos[1] = tVec[0];
335  Pos[2] = tVec[1];
336 
337  } // TrkLineFit()
geo::Length_t WireCoordinate(double YPos, double ZPos, geo::PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
geo::Geometry const * m_geometry
process_name opflash particleana ie x
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
process_name hit
Definition: cheaterreco.fcl:51
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:493
auto norm(Vector const &v)
Return norm of the specified vector.
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
float A
Definition: dedx.py:137

Member Data Documentation

double lar_cluster3d::PCASeedFinderAlg::m_gapDistance
private

Definition at line 61 of file PCASeedFinderAlg.h.

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

Definition at line 59 of file PCASeedFinderAlg.h.

double lar_cluster3d::PCASeedFinderAlg::m_minAllowedCosAng
private

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

Definition at line 63 of file PCASeedFinderAlg.h.

size_t lar_cluster3d::PCASeedFinderAlg::m_numSeed2DHits
private

Definition at line 62 of file PCASeedFinderAlg.h.

PrincipalComponentsAlg lar_cluster3d::PCASeedFinderAlg::m_pcaAlg
private

Definition at line 65 of file PCASeedFinderAlg.h.


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