LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
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::WireReadoutGeom const * m_wireReadoutGeom
 
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 29 of file PCASeedFinderAlg.h.

Constructor & Destructor Documentation

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

Constructor.

Parameters
pset

Definition at line 37 of file PCASeedFinderAlg.cxx.

References Get, fhicl::ParameterSet::get(), m_gapDistance, m_minAllowedCosAng, m_numSeed2DHits, and m_wireReadoutGeom.

38  : m_gapDistance(5.)
39  , m_numSeed2DHits(80)
40  , m_minAllowedCosAng(0.7)
41  , m_pcaAlg(pset.get<fhicl::ParameterSet>("PrincipalComponentsAlg"))
42  {
43  m_gapDistance = pset.get<double>("GapDistance", 5.);
44  m_numSeed2DHits = pset.get<size_t>("NumSeed2DHits", 80);
45  m_minAllowedCosAng = pset.get<double>("MinAllowedCosAng", 0.7);
47  }
cout<< "Opened file "<< fin<< " ixs= "<< ixs<< endl;if(ixs==0) hhh=(TH1F *) fff-> Get("h1")
Definition: AddMC.C:8
PrincipalComponentsAlg m_pcaAlg
geo::WireReadoutGeom const * m_wireReadoutGeom
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.

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().

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:232
PrincipalComponentsAlg m_pcaAlg
const EigenValues & getEigenValues() const
Definition: Cluster3D.h:242
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:326
void LineFit2DHits(const reco::HitPairListPtr &hitList, double XOrigin, TVector3 &Pos, TVector3 &Dir, double &ChiDOF) const
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:243
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 152 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().

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

Definition at line 212 of file PCASeedFinderAlg.cxx.

References m_wireReadoutGeom, norm, geo::WireReadoutGeom::Plane(), geo::PlaneID::Plane, sw, w, geo::WireID::Wire, geo::PlaneGeo::WireCoordinate(), geo::PlaneGeo::WirePitch(), and x.

Referenced by findTrackSeeds().

217  {
218  // The following is lifted from Bruce Baller to try to get better
219  // initial parameters for a candidate Seed. It is slightly reworked
220  // which is why it is included here instead of used as is.
221  //
222  // Linear fit using X as the independent variable. Hits to be fitted
223  // are passed in the hits vector in a pair form (X, WireID). The
224  // fitted track position at XOrigin is returned in the Pos vector.
225  // The direction cosines are returned in the Dir vector.
226  //
227  // SVD fit adapted from $ROOTSYS/tutorials/matrix/solveLinear.C
228  // Fit equation is w = A(X)v, where w is a vector of hit wires, A is
229  // a matrix to calculate a track projected to a point at X, and v is
230  // a vector (Yo, Zo, dY/dX, dZ/dX).
231  //
232  // Note: The covariance matrix should also be returned
233  // B. Baller August 2014
234 
235  // assume failure
236  ChiDOF = -1;
237 
238  // Make a set of 2D hits so we consider only unique hits
239  std::set<const reco::ClusterHit2D*> hit2DSet;
240 
241  for (const auto& hit3D : hit3DList) {
242  for (const auto& hit2D : hit3D->getHits())
243  hit2DSet.insert(hit2D);
244  }
245 
246  if (hit2DSet.size() < 4) return;
247 
248  const unsigned int nvars = 4;
249  unsigned int npts = 3 * hit3DList.size();
250 
251  TMatrixD A(npts, nvars);
252  // vector holding the Wire number
253  TVectorD w(npts);
254  unsigned short ninpl[3] = {0};
255  unsigned short nok = 0;
256  unsigned short iht(0);
257 
258  // Loop over the 2D hits in the above
259  for (const auto& hit : hit2DSet) {
260  geo::WireID const& wireID = hit->WireID();
261  auto const& plane = m_wireReadoutGeom->Plane(wireID);
262  unsigned int ipl = wireID.Plane;
263 
264  // get the wire plane offset
265  double const off = plane.WireCoordinate(geo::Point_t{0, 0, 0});
266 
267  // get the "cosine-like" component
268  double const cw = plane.WireCoordinate(geo::Point_t{0, 1, 0}) - off;
269 
270  // the "sine-like" component
271  double const sw = plane.WireCoordinate(geo::Point_t{0, 0, 1}) - off;
272 
273  double const x = hit->getXPosition() - XOrigin;
274 
275  A[iht][0] = cw;
276  A[iht][1] = sw;
277  A[iht][2] = cw * x;
278  A[iht][3] = sw * x;
279  w[iht] = wireID.Wire - off;
280 
281  ++ninpl[ipl];
282 
283  // need at least two points in a plane
284  if (ninpl[ipl] == 2) ++nok;
285 
286  iht++;
287  }
288 
289  // need at least 2 planes with at least two points
290  if (nok < 2) return;
291 
292  TDecompSVD svd(A);
293  bool ok;
294  TVectorD tVec = svd.Solve(w, ok);
295 
296  ChiDOF = 0;
297 
298  // not enough points to calculate Chisq
299  if (npts <= 4) return;
300 
301  for (const auto& hit : hit2DSet) {
302  geo::WireID const& wireID = hit->WireID();
303  auto const& plane = m_wireReadoutGeom->Plane(wireID);
304  double const off = plane.WireCoordinate(geo::Point_t{0, 0, 0});
305  double const cw = plane.WireCoordinate(geo::Point_t{0, 1, 0}) - off;
306  double const sw = plane.WireCoordinate(geo::Point_t{0, 0, 1}) - off;
307  double const x = hit->getXPosition() - XOrigin;
308  double const ypr = tVec[0] + tVec[2] * x;
309  double const zpr = tVec[1] + tVec[3] * x;
310  double const diff = ypr * cw + zpr * sw - (wireID.Wire - off);
311  ChiDOF += diff * diff;
312  }
313 
314  auto const& plane = m_wireReadoutGeom->Plane({0, 0, 0});
315  float werr2 = plane.WirePitch() * plane.WirePitch();
316  ChiDOF /= werr2;
317  ChiDOF /= (float)(npts - 4);
318 
319  double norm = sqrt(1 + tVec[2] * tVec[2] + tVec[3] * tVec[3]);
320  Dir[0] = 1 / norm;
321  Dir[1] = tVec[2] / norm;
322  Dir[2] = tVec[3] / norm;
323 
324  Pos[0] = XOrigin;
325  Pos[1] = tVec[0];
326  Pos[2] = tVec[1];
327 
328  } // TrkLineFit()
Float_t x
Definition: compare.C:6
double WireCoordinate(Point_t const &point) const
Returns the coordinate of the point on the plane, in wire units.
Definition: PlaneGeo.h:704
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:430
geo::WireReadoutGeom const * m_wireReadoutGeom
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:373
Detector simulation of raw signals on wires.
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Definition: geo_vectors.h:180
Float_t sw
Definition: plot.C:20
Float_t norm
PlaneGeo const & Plane(TPCID const &tpcid, View_t view) const
Returns the specified wire.
Float_t w
Definition: plot.C:20
double WirePitch() const
Return the wire pitch (in centimeters). It is assumed constant.
Definition: PlaneGeo.h:312

Member Data Documentation

double lar_cluster3d::PCASeedFinderAlg::m_gapDistance
private

Definition at line 59 of file PCASeedFinderAlg.h.

Referenced by getHitsAtEnd(), and PCASeedFinderAlg().

double lar_cluster3d::PCASeedFinderAlg::m_minAllowedCosAng
private

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

Definition at line 61 of file PCASeedFinderAlg.h.

Referenced by getHitsAtEnd(), and PCASeedFinderAlg().

size_t lar_cluster3d::PCASeedFinderAlg::m_numSeed2DHits
private

Definition at line 60 of file PCASeedFinderAlg.h.

Referenced by getHitsAtEnd(), and PCASeedFinderAlg().

PrincipalComponentsAlg lar_cluster3d::PCASeedFinderAlg::m_pcaAlg
private

Definition at line 63 of file PCASeedFinderAlg.h.

Referenced by findTrackSeeds(), and getHitsAtEnd().

geo::WireReadoutGeom const* lar_cluster3d::PCASeedFinderAlg::m_wireReadoutGeom
private

Definition at line 57 of file PCASeedFinderAlg.h.

Referenced by LineFit2DHits(), and PCASeedFinderAlg().


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