ParallelHitsSeedFinderAlg.cxx
Go to the documentation of this file.
1 /**
2  * @file ParallelHitsSeedFinderAlg.cxx
3  *
4  * @brief Implementation of the Seed Finder Algorithm
5  * The intent of this algorithm is to take an input list of 3D space points and from those
6  * to find candidate track start points and directions
7  */
8 
10 
11 // Framework includes
12 #include "fhiclcpp/ParameterSet.h"
13 
14 // LArSoft includes
16 
17 // std includes
18 #include <memory>
19 
20 //------------------------------------------------------------------------------------------------------------------------------------------
21 
22 //------------------------------------------------------------------------------------------------------------------------------------------
23 // implementation follows
24 
25 namespace lar_cluster3d {
26 
28  : m_maxNumEdgeHits(1000)
29  , m_gapDistance(20.)
30  , m_numSeed2DHits(80)
31  , m_pcaAlg(pset.get<fhicl::ParameterSet>("PrincipalComponentsAlg"))
32  {
33  m_maxNumEdgeHits = pset.get<size_t>("MaxNumEdgeHits", 1000);
34  m_gapDistance = pset.get<double>("GapDistance", 20.);
35  m_numSeed2DHits = pset.get<size_t>("NumSeed2DHits", 80);
36  }
37 
38  bool
40  reco::PrincipalComponents& inputPCA,
41  SeedHitPairListPairVec& seedHitPairVec) const
42  {
43  // This routine can fail...
44  bool foundGoodSeeds(false);
45 
46  // Make sure we are using the right pca
47  reco::PrincipalComponents pca = inputPCA;
48 
49  if (pca.getSvdOK()) {
50  // Presume CR muons will be "downward going"...
51  if (pca.getEigenVectors().row(2)(1) > 0.) pca.flipAxis(0);
52 
53  // This routine is typically called when there are LOTS of hits... so we are going to try
54  // to reduce the number of operations on the full list as much as possible. However, we
55  // really need the input hit list to be sorted by th input PCA so do that now
56  m_pcaAlg.PCAAnalysis_calc3DDocas(inputHitPairListPtr, pca);
57 
58  // Use this info to sort the hits along the principle axis
59  // Note that this will sort hits from the "middle" to the "outside"
60  inputHitPairListPtr.sort(SeedFinderAlgBase::Sort3DHitsByArcLen3D());
61 
62  // We need to determine the number of hits to drop... and this is really driven by the number of unique
63  // 2D hits we want to keep at one end of the cluster. So, make some containers and do some looping
64  reco::HitPairListPtr seedHit3DList;
65  std::set<const reco::ClusterHit2D*> hit2DSet;
66 
67  // Look for numSeed2DHits which are continuous
68  double lastArcLen = inputHitPairListPtr.front()->getArclenToPoca();
69 
70  for (const auto& hit3D : inputHitPairListPtr) {
71  double arcLen = hit3D->getArclenToPoca();
72 
73  if (fabs(arcLen - lastArcLen) > m_gapDistance) {
74  seedHit3DList.clear();
75  hit2DSet.clear();
76  }
77 
78  seedHit3DList.push_back(hit3D);
79 
80  for (const auto& hit2D : hit3D->getHits()) {
81  hit2DSet.insert(hit2D);
82  }
83 
84  if (hit2DSet.size() > m_numSeed2DHits) break;
85 
86  lastArcLen = arcLen;
87  }
88 
89  // We require a minimum number of seed hits in order to proceed
90  if (hit2DSet.size() > m_numSeed2DHits) {
91  // The above derivation determines the number of hits to keep each side of the cloud
92  size_t num3DHitsToKeep = std::min(2 * seedHit3DList.size(), inputHitPairListPtr.size());
93  size_t numEdgeHits = std::min(size_t(num3DHitsToKeep / 2), m_maxNumEdgeHits);
94 
95  // Get an iterator for the hits
96  reco::HitPairListPtr::iterator edgeHitItr = inputHitPairListPtr.begin();
97 
98  std::advance(edgeHitItr, numEdgeHits);
99 
100  // Make a container for copying in the edge hits and size it to hold all the hits
101  reco::HitPairListPtr hit3DList;
102 
103  hit3DList.resize(2 * numEdgeHits);
104 
105  // Copy the low edge hit range into the list
106  reco::HitPairListPtr::iterator nextHit3DItr =
107  std::copy(inputHitPairListPtr.begin(), edgeHitItr, hit3DList.begin());
108 
109  // reset the "seed hits"
110  seedHit3DList.clear();
111  seedHit3DList.resize(numEdgeHits);
112 
113  std::copy(inputHitPairListPtr.begin(), edgeHitItr, seedHit3DList.begin());
114 
115  // Now advance the iterator into the main container and copy the rest of the elements
116  std::advance(edgeHitItr, inputHitPairListPtr.size() - 2 * numEdgeHits);
117 
118  std::copy(edgeHitItr, inputHitPairListPtr.end(), nextHit3DItr);
119 
120  // At this point we should now have trimmed out the bulk of the 3D hits from the middle
121  // of the input cloud of hits. Next step is to rerun the PCA on our reduced set of hits
123 
124  m_pcaAlg.PCAAnalysis_3D(hit3DList, seedPCA, false);
125 
126  if (seedPCA.getSvdOK()) {
127  // Still looking to point "down"
128  if (seedPCA.getEigenVectors().row(2)(1) > 0.) seedPCA.flipAxis(0);
129 
130  // Recompute the 3D docas and arc lengths
131  m_pcaAlg.PCAAnalysis_calc3DDocas(hit3DList, seedPCA);
132 
133  // Now sort hits in regular order
134  //hit3DList.sort(SeedFinderAlgBase::Sort3DHitsByArcLen3D());
135  seedHit3DList.sort(SeedFinderAlgBase::Sort3DHitsByArcLen3D());
136 
137  // Now translate the seedCenter by the arc len to the first hit
138  double seedDir[3] = {seedPCA.getEigenVectors().row(2)(0),
139  seedPCA.getEigenVectors().row(2)(1),
140  seedPCA.getEigenVectors().row(2)(2)};
141  double seedStart[3] = {seedHit3DList.front()->getX(),
142  seedHit3DList.front()->getY(),
143  seedHit3DList.front()->getZ()};
144 
145  // Move from the first hit to the halfway point but from the first hit, not from the axis position
146  double halfArcLen = 0.5 * fabs(seedHit3DList.back()->getArclenToPoca() -
147  seedHit3DList.front()->getArclenToPoca());
148 
149  seedStart[0] += halfArcLen * seedDir[0];
150  seedStart[1] += halfArcLen * seedDir[1];
151  seedStart[2] += halfArcLen * seedDir[2];
152 
153  for (const auto& hit3D : seedHit3DList)
154  hit3D->setStatusBit(0x40000000);
155 
156  seedHitPairVec.emplace_back(std::pair<recob::Seed, reco::HitPairListPtr>(
157  recob::Seed(seedStart, seedDir), seedHit3DList));
158 
159  inputPCA = seedPCA;
160 
161  foundGoodSeeds = true;
162  }
163  }
164  }
165 
166  return foundGoodSeeds;
167  }
168 
169 } // namespace lar_cluster3d
intermediate_table::iterator iterator
void PCAAnalysis_calc3DDocas(const reco::HitPairListPtr &hitPairVector, const reco::PrincipalComponents &pca) const
bool getSvdOK() const
Definition: Cluster3D.h:244
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
double m_gapDistance
Maximum allowed distance between hits.
void flipAxis(size_t axis)
Definition: Cluster3D.cxx:208
size_t m_maxNumEdgeHits
Maximum number hits each end of PCA axis.
ParallelHitsSeedFinderAlg(fhicl::ParameterSet const &pset)
Constructor.
T get(std::string const &key) const
Definition: ParameterSet.h:271
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:335
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
size_t m_numSeed2DHits
Number 2D seed hits desired.
T copy(T const &v)
std::vector< SeedHitPairListPair > SeedHitPairListPairVec
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
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.
const EigenVectors & getEigenVectors() const
Definition: Cluster3D.h:247