LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
DBScanAlg_tool.cc
Go to the documentation of this file.
1 
8 // Framework Includes
10 #include "cetlib/search_path.h"
11 #include "cetlib/cpu_timer.h"
12 
14 
15 // LArSoft includes
20 
21 // std includes
22 #include <string>
23 #include <functional>
24 #include <iostream>
25 #include <memory>
26 
27 //------------------------------------------------------------------------------------------------------------------------------------------
28 // implementation follows
29 
30 namespace lar_cluster3d {
31 
35 class DBScanAlg : virtual public IClusterAlg
36 {
37 public:
43  explicit DBScanAlg(fhicl::ParameterSet const &pset);
44 
48  ~DBScanAlg();
49 
50  void configure(const fhicl::ParameterSet&) override;
51 
58  void Cluster3DHits(reco::HitPairList& hitPairList,
59  reco::ClusterParametersList& clusterParametersList) const override;
60 
67  void Cluster3DHits(reco::HitPairListPtr& hitPairList,
68  reco::ClusterParametersList& clusterParametersList) const override;
69 
73  float getTimeToExecute(IClusterAlg::TimeValues index) const override {return m_timeVector.at(index);}
74 
75 private:
76 
83  size_t) const;
84 
89  size_t m_minPairPts;
90  mutable std::vector<float> m_timeVector;
91 
92  ClusterParamsBuilder m_clusterBuilder; // Common cluster builder tool
93  kdTree m_kdTree; // For the kdTree
94 };
95 
97  m_clusterBuilder(pset.get<fhicl::ParameterSet>("ClusterParamsBuilder")),
98  m_kdTree(pset.get<fhicl::ParameterSet>("kdTree"))
99 {
100  this->configure(pset);
101 }
102 
103 //------------------------------------------------------------------------------------------------------------------------------------------
104 
106 {
107 }
108 
109 //------------------------------------------------------------------------------------------------------------------------------------------
110 
112 {
113  m_enableMonitoring = pset.get<bool> ("EnableMonitoring", true );
114  m_minPairPts = pset.get<size_t>("MinPairPts", 2 );
115 }
116 
118  reco::ClusterParametersList& clusterParametersList) const
119 {
124  cet::cpu_timer theClockDBScan;
125 
126  m_timeVector.resize(NUMTIMEVALUES, 0.);
127 
128  // DBScan is driven of its "epsilon neighborhood". Computing adjacency within DBScan can be time
129  // consuming so the idea is the prebuild the adjaceny map and then run DBScan.
130  // We'll employ a kdTree to implement this scheme
131  kdTree::KdTreeNodeList kdTreeNodeContainer;
132  kdTree::KdTreeNode topNode = m_kdTree.BuildKdTree(hitPairList, kdTreeNodeContainer);
133 
135 
136  if (m_enableMonitoring) theClockDBScan.start();
137 
138  // Ok, here we go!
139  // The idea is to loop through all of the input 3D hits and do the clustering
140  for(const auto& hit : hitPairList)
141  {
142  // Check if the hit has already been visited
143  if (hit->getStatusBits() & reco::ClusterHit3D::CLUSTERVISITED) continue;
144 
145  // Mark as visited
147 
148  // Find the neighborhood for this hit
149  kdTree::CandPairList candPairList;
150  float bestDistance(std::numeric_limits<float>::max());
151 
152  m_kdTree.FindNearestNeighbors(hit.get(), topNode, candPairList, bestDistance);
153 
154  if (candPairList.size() < m_minPairPts)
155  {
156  hit->setStatusBit(reco::ClusterHit3D::CLUSTERNOISE);
157  }
158  else
159  {
160  // "Create" a new cluster and get a reference to it
161  clusterParametersList.push_back(reco::ClusterParameters());
162 
163  reco::ClusterParameters& curCluster = clusterParametersList.back();
164 
166  curCluster.addHit3D(hit.get());
167 
168  // expand the cluster
169  expandCluster(topNode, candPairList, curCluster, m_minPairPts);
170  }
171  }
172 
173  if (m_enableMonitoring)
174  {
175  theClockDBScan.stop();
176 
177  m_timeVector[RUNDBSCAN] = theClockDBScan.accumulated_real_time();
178  }
179 
180  // Initial clustering is done, now trim the list and get output parameters
181  cet::cpu_timer theClockBuildClusters;
182 
183  // Start clocks if requested
184  if (m_enableMonitoring) theClockBuildClusters.start();
185 
186  m_clusterBuilder.BuildClusterInfo(clusterParametersList);
187 
188  if (m_enableMonitoring)
189  {
190  theClockBuildClusters.stop();
191 
192  m_timeVector[BUILDCLUSTERINFO] = theClockBuildClusters.accumulated_real_time();
193  }
194 
195  mf::LogDebug("Cluster3D") << ">>>>> DBScan done, found " << clusterParametersList.size() << " clusters" << std::endl;
196 
197  return;
198 }
199 
201  reco::ClusterParametersList& clusterParametersList) const
202 {
207  cet::cpu_timer theClockDBScan;
208 
209  m_timeVector.resize(NUMTIMEVALUES, 0.);
210 
211  // DBScan is driven of its "epsilon neighborhood". Computing adjacency within DBScan can be time
212  // consuming so the idea is the prebuild the adjaceny map and then run DBScan.
213  // We'll employ a kdTree to implement this scheme
214  kdTree::KdTreeNodeList kdTreeNodeContainer;
215  kdTree::KdTreeNode topNode = m_kdTree.BuildKdTree(hitPairList, kdTreeNodeContainer);
216 
218 
219  if (m_enableMonitoring) theClockDBScan.start();
220 
221  // Ok, here we go!
222  // The idea is to loop through all of the input 3D hits and do the clustering
223  for(const auto& hit : hitPairList)
224  {
225  // Check if the hit has already been visited
226  if (hit->getStatusBits() & reco::ClusterHit3D::CLUSTERVISITED) continue;
227 
228  // Mark as visited
230 
231  // Find the neighborhood for this hit
232  kdTree::CandPairList candPairList;
233  float bestDistance(std::numeric_limits<float>::max());
234 
235  m_kdTree.FindNearestNeighbors(hit, topNode, candPairList, bestDistance);
236 
237  if (candPairList.size() < m_minPairPts)
238  {
239  hit->setStatusBit(reco::ClusterHit3D::CLUSTERNOISE);
240  }
241  else
242  {
243  // "Create" a new cluster and get a reference to it
244  clusterParametersList.push_back(reco::ClusterParameters());
245 
246  reco::ClusterParameters& curCluster = clusterParametersList.back();
247 
249  curCluster.addHit3D(hit);
250 
251  // expand the cluster
252  expandCluster(topNode, candPairList, curCluster, m_minPairPts);
253  }
254  }
255 
256  if (m_enableMonitoring)
257  {
258  theClockDBScan.stop();
259 
260  m_timeVector[RUNDBSCAN] = theClockDBScan.accumulated_real_time();
261  }
262 
263  // Initial clustering is done, now trim the list and get output parameters
264  cet::cpu_timer theClockBuildClusters;
265 
266  // Start clocks if requested
267  if (m_enableMonitoring) theClockBuildClusters.start();
268 
269  m_clusterBuilder.BuildClusterInfo(clusterParametersList);
270 
271  if (m_enableMonitoring)
272  {
273  theClockBuildClusters.stop();
274 
275  m_timeVector[BUILDCLUSTERINFO] = theClockBuildClusters.accumulated_real_time();
276  }
277 
278  mf::LogDebug("Cluster3D") << ">>>>> DBScan done, found " << clusterParametersList.size() << " clusters" << std::endl;
279 
280  return;
281 }
282 
284  kdTree::CandPairList& candPairList,
286  size_t minPts) const
287 {
288  // This is the main inside loop for the DBScan based clustering algorithm
289 
290  // Loop over added hits until list has been exhausted
291  while(!candPairList.empty())
292  {
293  // Dereference the point so we can see in the debugger...
294  const reco::ClusterHit3D* neighborHit = candPairList.front().second;
295 
296  // Process if we've not been here before
297  if (!(neighborHit->getStatusBits() & reco::ClusterHit3D::CLUSTERVISITED))
298  {
299  // set as visited
301 
302  // get the neighborhood around this point
303  kdTree::CandPairList neighborCandPairList;
304  float bestDistance(std::numeric_limits<float>::max());
305 
306  m_kdTree.FindNearestNeighbors(neighborHit, topNode, neighborCandPairList, bestDistance);
307 
308  // If the epsilon neighborhood of this point is large enough then add its points to our list
309  if (neighborCandPairList.size() >= minPts)
310  {
311  std::copy(neighborCandPairList.begin(),neighborCandPairList.end(),std::back_inserter(candPairList));
312  }
313  }
314 
315  // If the point is not yet in a cluster then we now add
316  if (!(neighborHit->getStatusBits() & reco::ClusterHit3D::CLUSTERATTACHED))
317  {
319  cluster.addHit3D(neighborHit);
320  }
321 
322  candPairList.pop_front();
323  }
324 
325  return;
326 }
327 
328 //------------------------------------------------------------------------------------------------------------------------------------------
329 
331 } // namespace lar_cluster3d
void expandCluster(const kdTree::KdTreeNode &, kdTree::CandPairList &, reco::ClusterParameters &, size_t) const
the main routine for DBScan
#define DEFINE_ART_CLASS_TOOL(tool)
Definition: ToolMacros.h:45
This algorithm will create and then cluster 3D hits using DBScan.
kdTree class definiton
Definition: kdTree.h:30
void configure(const fhicl::ParameterSet &) override
Interface for configuring the particular algorithm tool.
bool m_enableMonitoring
Data members to follow.
Declaration of signal hit object.
std::list< KdTreeNode > KdTreeNodeList
Definition: kdTree.h:58
Implements a kdTree for use in clustering.
size_t FindNearestNeighbors(const reco::ClusterHit3D *, const KdTreeNode &, CandPairList &, float &) const
Definition: kdTree.cxx:178
Labelled "noise" by a clustering algorithm.
Definition: Cluster3D.h:101
void BuildClusterInfo(reco::ClusterParametersList &clusterParametersList) const
Given the results of running DBScan, format the clusters so that they can be easily transferred back ...
Cluster finding and building.
IClusterAlg interface class definiton.
Definition: IClusterAlg.h:25
unsigned int getStatusBits() const
Definition: Cluster3D.h:146
std::list< std::unique_ptr< reco::ClusterHit3D >> HitPairList
Definition: Cluster3D.h:321
define a kd tree node
Definition: kdTree.h:107
Int_t max
Definition: plot.C:27
ClusterParamsBuilder class definiton.
parameter set interface
T get(std::string const &key) const
Definition: ParameterSet.h:231
TimeValues
enumerate the possible values for time checking if monitoring timing
Definition: IClusterAlg.h:61
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:317
This provides an art tool interface definition for 3D Cluster algorithms.
Detector simulation of raw signals on wires.
std::list< CandPair > CandPairList
Definition: kdTree.h:70
void Cluster3DHits(reco::HitPairList &hitPairList, reco::ClusterParametersList &clusterParametersList) const override
Given a set of recob hits, run DBscan to form 3D clusters.
Utility object to perform functions of association.
DBScanAlg(fhicl::ParameterSet const &pset)
Constructor.
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
DBScanAlg class definiton.
float getTimeToExecute(IClusterAlg::TimeValues index) const override
If monitoring, recover the time to execute a particular function.
ClusterParamsBuilder m_clusterBuilder
float getTimeToExecute() const
Definition: kdTree.h:86
"visited" by a clustering algorithm
Definition: Cluster3D.h:100
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:120
std::list< ClusterParameters > ClusterParametersList
Definition: Cluster3D.h:381
attached to a cluster
Definition: Cluster3D.h:102
void addHit3D(const reco::ClusterHit3D *hit3D)
Definition: Cluster3D.h:434
void setStatusBit(unsigned bits) const
Definition: Cluster3D.h:165