All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DBScanAlg_tool.cc
Go to the documentation of this file.
1 /**
2  * @file Cluster3D_module.cc
3  *
4  * @brief Producer module to create 3D clusters from input hits
5  *
6  */
7 
8 // Framework Includes
9 #include "art/Framework/Services/Registry/ServiceHandle.h"
10 #include "art/Utilities/make_tool.h"
11 #include "art/Utilities/ToolMacros.h"
12 #include "cetlib/cpu_timer.h"
13 #include "fhiclcpp/ParameterSet.h"
14 #include "messagefacility/MessageLogger/MessageLogger.h"
15 
16 // LArSoft includes
22 
23 // std includes
24 #include <memory>
25 
26 //------------------------------------------------------------------------------------------------------------------------------------------
27 // implementation follows
28 
29 namespace lar_cluster3d {
30 
31 /**
32  * @brief DBScanAlg class definiton
33  */
34 class DBScanAlg : virtual public IClusterAlg
35 {
36 public:
37  /**
38  * @brief Constructor
39  *
40  * @param pset
41  */
42  explicit DBScanAlg(fhicl::ParameterSet const &pset);
43 
44  /**
45  * @brief Destructor
46  */
47  ~DBScanAlg();
48 
49  void configure(const fhicl::ParameterSet&) override;
50 
51  /**
52  * @brief Given a set of recob hits, run DBscan to form 3D clusters
53  *
54  * @param hitPairList The input list of 3D hits to run clustering on
55  * @param clusterParametersList A list of cluster objects (parameters from associated hits)
56  */
57  void Cluster3DHits(reco::HitPairList& hitPairList,
58  reco::ClusterParametersList& clusterParametersList) const override;
59 
60  /**
61  * @brief Given a set of recob hits, run DBscan to form 3D clusters
62  *
63  * @param hitPairList The input list of 3D hits to run clustering on
64  * @param clusterParametersList A list of cluster objects (parameters from associated hits)
65  */
66  void Cluster3DHits(reco::HitPairListPtr& hitPairList,
67  reco::ClusterParametersList& clusterParametersList) const override;
68 
69  /**
70  * @brief If monitoring, recover the time to execute a particular function
71  */
72  float getTimeToExecute(IClusterAlg::TimeValues index) const override {return m_timeVector[index];}
73 
74 private:
75 
76  /**
77  * @brief the main routine for DBScan
78  */
82  size_t) const;
83 
84  /**
85  * @brief Data members to follow
86  */
87  bool m_enableMonitoring; ///<
88  size_t m_minPairPts;
89  mutable std::vector<float> m_timeVector; ///<
90 
91  std::unique_ptr<lar_cluster3d::IClusterParametersBuilder> m_clusterBuilder; ///< Common cluster builder tool
92  kdTree m_kdTree; // For the kdTree
93 };
94 
95 DBScanAlg::DBScanAlg(fhicl::ParameterSet const &pset)
96 {
97  this->configure(pset);
98 }
99 
100 //------------------------------------------------------------------------------------------------------------------------------------------
101 
103 {
104 }
105 
106 //------------------------------------------------------------------------------------------------------------------------------------------
107 
108 void DBScanAlg::configure(fhicl::ParameterSet const &pset)
109 {
110  m_enableMonitoring = pset.get<bool> ("EnableMonitoring", true );
111  m_minPairPts = pset.get<size_t>("MinPairPts", 2 );
112 
113  m_clusterBuilder = art::make_tool<lar_cluster3d::IClusterParametersBuilder>(pset.get<fhicl::ParameterSet>("ClusterParamsBuilder"));
114 
115  // Recover the parameter set for the kdTree
116  fhicl::ParameterSet kdTreeParams(pset.get<fhicl::ParameterSet>("kdTree"));
117 
118  // Now work out the maximum wire pitch
119  art::ServiceHandle<geo::Geometry const> geometry;
120 
121  // Returns the wire pitch per plane assuming they will be the same for all TPCs
122  std::vector<float> wirePitchVec(3,0.);
123 
124  wirePitchVec[0] = geometry->WirePitch(0);
125  wirePitchVec[1] = geometry->WirePitch(1);
126  wirePitchVec[2] = geometry->WirePitch(2);
127 
128  float maxBestDist = 1.99 * *std::max_element(wirePitchVec.begin(),wirePitchVec.end());
129 
130  kdTreeParams.put_or_replace<float>("RefLeafBestDist", maxBestDist);
131 
132  m_kdTree = kdTree(kdTreeParams);
133 }
134 
136  reco::ClusterParametersList& clusterParametersList) const
137 {
138  /**
139  * @brief Driver for processing input 2D hits, transforming to 3D hits and building lists
140  * of associated 3D hits (candidate 3D clusters)
141  */
142  cet::cpu_timer theClockDBScan;
143 
144  m_timeVector.resize(NUMTIMEVALUES, 0.);
145 
146  // DBScan is driven of its "epsilon neighborhood". Computing adjacency within DBScan can be time
147  // consuming so the idea is the prebuild the adjaceny map and then run DBScan.
148  // We'll employ a kdTree to implement this scheme
149  kdTree::KdTreeNodeList kdTreeNodeContainer;
150  kdTree::KdTreeNode topNode = m_kdTree.BuildKdTree(hitPairList, kdTreeNodeContainer);
151 
153 
154  if (m_enableMonitoring) theClockDBScan.start();
155 
156  // Ok, here we go!
157  // The idea is to loop through all of the input 3D hits and do the clustering
158  for(const auto& hit : hitPairList)
159  {
160  // Check if the hit has already been visited
161  if (hit.getStatusBits() & reco::ClusterHit3D::CLUSTERVISITED) continue;
162 
163  // Mark as visited
165 
166  // Find the neighborhood for this hit
167  kdTree::CandPairList candPairList;
168  float bestDistance(std::numeric_limits<float>::max());
169 
170  m_kdTree.FindNearestNeighbors(&hit, topNode, candPairList, bestDistance);
171 
172  if (candPairList.size() < m_minPairPts)
173  {
175  }
176  else
177  {
178  // "Create" a new cluster and get a reference to it
179  clusterParametersList.push_back(reco::ClusterParameters());
180 
181  reco::ClusterParameters& curCluster = clusterParametersList.back();
182 
184  curCluster.addHit3D(&hit);
185 
186  // expand the cluster
187  expandCluster(topNode, candPairList, curCluster, m_minPairPts);
188  }
189  }
190 
191  if (m_enableMonitoring)
192  {
193  theClockDBScan.stop();
194 
195  m_timeVector[RUNDBSCAN] = theClockDBScan.accumulated_real_time();
196  }
197 
198  // Initial clustering is done, now trim the list and get output parameters
199  cet::cpu_timer theClockBuildClusters;
200 
201  // Start clocks if requested
202  if (m_enableMonitoring) theClockBuildClusters.start();
203 
204  m_clusterBuilder->BuildClusterInfo(clusterParametersList);
205 
206  if (m_enableMonitoring)
207  {
208  theClockBuildClusters.stop();
209 
210  m_timeVector[BUILDCLUSTERINFO] = theClockBuildClusters.accumulated_real_time();
211  }
212 
213  mf::LogDebug("Cluster3D") << ">>>>> DBScan done, found " << clusterParametersList.size() << " clusters" << std::endl;
214 
215  return;
216 }
217 
219  reco::ClusterParametersList& clusterParametersList) const
220 {
221  /**
222  * @brief Driver for processing input 2D hits, transforming to 3D hits and building lists
223  * of associated 3D hits (candidate 3D clusters)
224  */
225  cet::cpu_timer theClockDBScan;
226 
227  m_timeVector.resize(NUMTIMEVALUES, 0.);
228 
229  // DBScan is driven of its "epsilon neighborhood". Computing adjacency within DBScan can be time
230  // consuming so the idea is the prebuild the adjaceny map and then run DBScan.
231  // We'll employ a kdTree to implement this scheme
232  kdTree::KdTreeNodeList kdTreeNodeContainer;
233  kdTree::KdTreeNode topNode = m_kdTree.BuildKdTree(hitPairList, kdTreeNodeContainer);
234 
236 
237  if (m_enableMonitoring) theClockDBScan.start();
238 
239  // Ok, here we go!
240  // The idea is to loop through all of the input 3D hits and do the clustering
241  for(const auto& hit : hitPairList)
242  {
243  // Check if the hit has already been visited
244  if (hit->getStatusBits() & reco::ClusterHit3D::CLUSTERVISITED) continue;
245 
246  // Mark as visited
248 
249  // Find the neighborhood for this hit
250  kdTree::CandPairList candPairList;
251  float bestDistance(std::numeric_limits<float>::max());
252 
253  m_kdTree.FindNearestNeighbors(hit, topNode, candPairList, bestDistance);
254 
255  if (candPairList.size() < m_minPairPts)
256  {
257  hit->setStatusBit(reco::ClusterHit3D::CLUSTERNOISE);
258  }
259  else
260  {
261  // "Create" a new cluster and get a reference to it
262  clusterParametersList.push_back(reco::ClusterParameters());
263 
264  reco::ClusterParameters& curCluster = clusterParametersList.back();
265 
267  curCluster.addHit3D(hit);
268 
269  // expand the cluster
270  expandCluster(topNode, candPairList, curCluster, m_minPairPts);
271  }
272  }
273 
274  if (m_enableMonitoring)
275  {
276  theClockDBScan.stop();
277 
278  m_timeVector[RUNDBSCAN] = theClockDBScan.accumulated_real_time();
279  }
280 
281  // Initial clustering is done, now trim the list and get output parameters
282  cet::cpu_timer theClockBuildClusters;
283 
284  // Start clocks if requested
285  if (m_enableMonitoring) theClockBuildClusters.start();
286 
287  m_clusterBuilder->BuildClusterInfo(clusterParametersList);
288 
289  if (m_enableMonitoring)
290  {
291  theClockBuildClusters.stop();
292 
293  m_timeVector[BUILDCLUSTERINFO] = theClockBuildClusters.accumulated_real_time();
294  }
295 
296  mf::LogDebug("Cluster3D") << ">>>>> DBScan done, found " << clusterParametersList.size() << " clusters" << std::endl;
297 
298  return;
299 }
300 
302  kdTree::CandPairList& candPairList,
304  size_t minPts) const
305 {
306  // This is the main inside loop for the DBScan based clustering algorithm
307 
308  // Loop over added hits until list has been exhausted
309  while(!candPairList.empty())
310  {
311  // Dereference the point so we can see in the debugger...
312  const reco::ClusterHit3D* neighborHit = candPairList.front().second;
313 
314  // Process if we've not been here before
315  if (!(neighborHit->getStatusBits() & reco::ClusterHit3D::CLUSTERVISITED))
316  {
317  // set as visited
319 
320  // get the neighborhood around this point
321  kdTree::CandPairList neighborCandPairList;
322  float bestDistance(std::numeric_limits<float>::max());
323 
324  m_kdTree.FindNearestNeighbors(neighborHit, topNode, neighborCandPairList, bestDistance);
325 
326  // If the epsilon neighborhood of this point is large enough then add its points to our list
327  if (neighborCandPairList.size() >= minPts)
328  {
329  std::copy(neighborCandPairList.begin(),neighborCandPairList.end(),std::back_inserter(candPairList));
330  }
331  }
332 
333  // If the point is not yet in a cluster then we now add
334  if (!(neighborHit->getStatusBits() & reco::ClusterHit3D::CLUSTERATTACHED))
335  {
337  cluster.addHit3D(neighborHit);
338  }
339 
340  candPairList.pop_front();
341  }
342 
343  return;
344 }
345 
346 //------------------------------------------------------------------------------------------------------------------------------------------
347 
348 DEFINE_ART_CLASS_TOOL(DBScanAlg)
349 } // namespace lar_cluster3d
void expandCluster(const kdTree::KdTreeNode &, kdTree::CandPairList &, reco::ClusterParameters &, size_t) const
the main routine for DBScan
std::list< reco::ClusterHit3D > HitPairList
Definition: Cluster3D.h:338
kdTree class definiton
Definition: kdTree.h:30
void configure(const fhicl::ParameterSet &) override
Interface for configuring the particular algorithm tool.
const geo::GeometryCore * geometry
bool m_enableMonitoring
Data members to follow.
process_name cluster
Definition: cheaterreco.fcl:51
float getTimeToExecute(IClusterAlg::TimeValues index) const override
If monitoring, recover the time to execute a particular function.
std::list< KdTreeNode > KdTreeNodeList
Definition: kdTree.h:67
Implements a kdTree for use in clustering.
size_t FindNearestNeighbors(const reco::ClusterHit3D *, const KdTreeNode &, CandPairList &, float &) const
Definition: kdTree.cxx:170
Labelled &quot;noise&quot; by a clustering algorithm.
Definition: Cluster3D.h:107
process_name hit
Definition: cheaterreco.fcl:51
IClusterAlg interface class definiton.
Definition: IClusterAlg.h:25
unsigned int getStatusBits() const
Definition: Cluster3D.h:156
define a kd tree node
Definition: kdTree.h:118
void Cluster3DHits(reco::HitPairList &hitPairList, reco::ClusterParametersList &clusterParametersList) const override
Given a set of recob hits, run DBscan to form 3D clusters.
TimeValues
enumerate the possible values for time checking if monitoring timing
Definition: IClusterAlg.h:61
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:334
This provides an art tool interface definition for 3D Cluster algorithms.
std::unique_ptr< lar_cluster3d::IClusterParametersBuilder > m_clusterBuilder
Common cluster builder tool.
std::list< CandPair > CandPairList
Definition: kdTree.h:79
DBScanAlg(fhicl::ParameterSet const &pset)
Constructor.
T copy(T const &v)
DBScanAlg class definiton.
float getTimeToExecute() const
Definition: kdTree.h:95
&quot;visited&quot; by a clustering algorithm
Definition: Cluster3D.h:106
std::vector< float > m_timeVector
KdTreeNode & BuildKdTree(Hit3DVec::iterator, Hit3DVec::iterator, KdTreeNodeList &, int depth=0) const
Given an input set of ClusterHit3D objects, build a kd tree structure.
Definition: kdTree.cxx:112
BEGIN_PROLOG don t mess with this pandoraTrackGausCryoW true
art framework interface to geometry description
std::list< ClusterParameters > ClusterParametersList
Definition: Cluster3D.h:403
attached to a cluster
Definition: Cluster3D.h:108
void addHit3D(const reco::ClusterHit3D *hit3D)
Definition: Cluster3D.h:456
void setStatusBit(unsigned bits) const
Definition: Cluster3D.h:179