LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
DBScanAlg_tool.cc
Go to the documentation of this file.
1 
8 // Framework Includes
12 #include "cetlib/cpu_timer.h"
13 #include "fhiclcpp/ParameterSet.h"
15 
16 // LArSoft includes
23 
24 // std includes
25 #include <memory>
26 
27 //------------------------------------------------------------------------------------------------------------------------------------------
28 // implementation follows
29 
30 namespace lar_cluster3d {
31 
35  class DBScanAlg : public IClusterAlg {
36  public:
42  explicit DBScanAlg(fhicl::ParameterSet const& pset);
43 
50  void Cluster3DHits(reco::HitPairList& hitPairList,
51  reco::ClusterParametersList& clusterParametersList) const override;
52 
59  void Cluster3DHits(reco::HitPairListPtr& hitPairList,
60  reco::ClusterParametersList& clusterParametersList) const override;
61 
65  float getTimeToExecute(IClusterAlg::TimeValues index) const override
66  {
67  return m_timeVector[index];
68  }
69 
70  private:
77  size_t) const;
78 
83  size_t m_minPairPts;
84  mutable std::vector<float> m_timeVector;
85 
86  std::unique_ptr<lar_cluster3d::IClusterParametersBuilder>
88  kdTree m_kdTree; // For the kdTree
89  };
90 
92  {
93  m_enableMonitoring = pset.get<bool>("EnableMonitoring", true);
94  m_minPairPts = pset.get<size_t>("MinPairPts", 2);
95 
96  m_clusterBuilder = art::make_tool<lar_cluster3d::IClusterParametersBuilder>(
97  pset.get<fhicl::ParameterSet>("ClusterParamsBuilder"));
98 
99  // Recover the parameter set for the kdTree
100  fhicl::ParameterSet kdTreeParams(pset.get<fhicl::ParameterSet>("kdTree"));
101 
102  // Now work out the maximum wire pitch
103  auto const& wireReadoutGeom = art::ServiceHandle<geo::WireReadout>()->Get();
104 
105  // Returns the wire pitch per plane assuming they will be the same for all TPCs
106  constexpr geo::TPCID tpcid{0, 0};
107  std::vector<double> const wirePitchVec{
108  wireReadoutGeom.Plane(geo::PlaneID{tpcid, 0}).WirePitch(),
109  wireReadoutGeom.Plane(geo::PlaneID{tpcid, 1}).WirePitch(),
110  wireReadoutGeom.Plane(geo::PlaneID{tpcid, 2}).WirePitch()};
111 
112  float maxBestDist = 1.99 * *std::max_element(wirePitchVec.begin(), wirePitchVec.end());
113 
114  kdTreeParams.put_or_replace<float>("RefLeafBestDist", maxBestDist);
115 
116  m_kdTree = kdTree(kdTreeParams);
117  }
118 
120  reco::ClusterParametersList& clusterParametersList) const
121  {
126  cet::cpu_timer theClockDBScan;
127 
128  m_timeVector.resize(NUMTIMEVALUES, 0.);
129 
130  // DBScan is driven of its "epsilon neighborhood". Computing adjacency within DBScan can be time
131  // consuming so the idea is the prebuild the adjaceny map and then run DBScan.
132  // We'll employ a kdTree to implement this scheme
133  kdTree::KdTreeNodeList kdTreeNodeContainer;
134  kdTree::KdTreeNode topNode = m_kdTree.BuildKdTree(hitPairList, kdTreeNodeContainer);
135 
137 
138  if (m_enableMonitoring) theClockDBScan.start();
139 
140  // Ok, here we go!
141  // The idea is to loop through all of the input 3D hits and do the clustering
142  for (const auto& hit : hitPairList) {
143  // Check if the hit has already been visited
144  if (hit.getStatusBits() & reco::ClusterHit3D::CLUSTERVISITED) continue;
145 
146  // Mark as visited
148 
149  // Find the neighborhood for this hit
150  kdTree::CandPairList candPairList;
151  float bestDistance(std::numeric_limits<float>::max());
152 
153  m_kdTree.FindNearestNeighbors(&hit, topNode, candPairList, bestDistance);
154 
155  if (candPairList.size() < m_minPairPts) {
157  }
158  else {
159  // "Create" a new cluster and get a reference to it
160  clusterParametersList.push_back(reco::ClusterParameters());
161 
162  reco::ClusterParameters& curCluster = clusterParametersList.back();
163 
165  curCluster.addHit3D(&hit);
166 
167  // expand the cluster
168  expandCluster(topNode, candPairList, curCluster, m_minPairPts);
169  }
170  }
171 
172  if (m_enableMonitoring) {
173  theClockDBScan.stop();
174 
175  m_timeVector[RUNDBSCAN] = theClockDBScan.accumulated_real_time();
176  }
177 
178  // Initial clustering is done, now trim the list and get output parameters
179  cet::cpu_timer theClockBuildClusters;
180 
181  // Start clocks if requested
182  if (m_enableMonitoring) theClockBuildClusters.start();
183 
184  m_clusterBuilder->BuildClusterInfo(clusterParametersList);
185 
186  if (m_enableMonitoring) {
187  theClockBuildClusters.stop();
188 
189  m_timeVector[BUILDCLUSTERINFO] = theClockBuildClusters.accumulated_real_time();
190  }
191 
192  mf::LogDebug("Cluster3D") << ">>>>> DBScan done, found " << clusterParametersList.size()
193  << " clusters" << std::endl;
194  }
195 
197  reco::ClusterParametersList& clusterParametersList) const
198  {
203  cet::cpu_timer theClockDBScan;
204 
205  m_timeVector.resize(NUMTIMEVALUES, 0.);
206 
207  // DBScan is driven of its "epsilon neighborhood". Computing adjacency within DBScan can be time
208  // consuming so the idea is the prebuild the adjaceny map and then run DBScan.
209  // We'll employ a kdTree to implement this scheme
210  kdTree::KdTreeNodeList kdTreeNodeContainer;
211  kdTree::KdTreeNode topNode = m_kdTree.BuildKdTree(hitPairList, kdTreeNodeContainer);
212 
214 
215  if (m_enableMonitoring) theClockDBScan.start();
216 
217  // Ok, here we go!
218  // The idea is to loop through all of the input 3D hits and do the clustering
219  for (const auto& hit : hitPairList) {
220  // Check if the hit has already been visited
221  if (hit->getStatusBits() & reco::ClusterHit3D::CLUSTERVISITED) continue;
222 
223  // Mark as visited
225 
226  // Find the neighborhood for this hit
227  kdTree::CandPairList candPairList;
228  float bestDistance(std::numeric_limits<float>::max());
229 
230  m_kdTree.FindNearestNeighbors(hit, topNode, candPairList, bestDistance);
231 
232  if (candPairList.size() < m_minPairPts) {
233  hit->setStatusBit(reco::ClusterHit3D::CLUSTERNOISE);
234  }
235  else {
236  // "Create" a new cluster and get a reference to it
237  clusterParametersList.push_back(reco::ClusterParameters());
238 
239  reco::ClusterParameters& curCluster = clusterParametersList.back();
240 
242  curCluster.addHit3D(hit);
243 
244  // expand the cluster
245  expandCluster(topNode, candPairList, curCluster, m_minPairPts);
246  }
247  }
248 
249  if (m_enableMonitoring) {
250  theClockDBScan.stop();
251 
252  m_timeVector[RUNDBSCAN] = theClockDBScan.accumulated_real_time();
253  }
254 
255  // Initial clustering is done, now trim the list and get output parameters
256  cet::cpu_timer theClockBuildClusters;
257 
258  // Start clocks if requested
259  if (m_enableMonitoring) theClockBuildClusters.start();
260 
261  m_clusterBuilder->BuildClusterInfo(clusterParametersList);
262 
263  if (m_enableMonitoring) {
264  theClockBuildClusters.stop();
265 
266  m_timeVector[BUILDCLUSTERINFO] = theClockBuildClusters.accumulated_real_time();
267  }
268 
269  mf::LogDebug("Cluster3D") << ">>>>> DBScan done, found " << clusterParametersList.size()
270  << " clusters" << std::endl;
271  }
272 
274  kdTree::CandPairList& candPairList,
276  size_t minPts) const
277  {
278  // This is the main inside loop for the DBScan based clustering algorithm
279 
280  // Loop over added hits until list has been exhausted
281  while (!candPairList.empty()) {
282  // Dereference the point so we can see in the debugger...
283  const reco::ClusterHit3D* neighborHit = candPairList.front().second;
284 
285  // Process if we've not been here before
286  if (!(neighborHit->getStatusBits() & reco::ClusterHit3D::CLUSTERVISITED)) {
287  // set as visited
289 
290  // get the neighborhood around this point
291  kdTree::CandPairList neighborCandPairList;
292  float bestDistance(std::numeric_limits<float>::max());
293 
294  m_kdTree.FindNearestNeighbors(neighborHit, topNode, neighborCandPairList, bestDistance);
295 
296  // If the epsilon neighborhood of this point is large enough then add its points to our list
297  if (neighborCandPairList.size() >= minPts) {
298  std::copy(neighborCandPairList.begin(),
299  neighborCandPairList.end(),
300  std::back_inserter(candPairList));
301  }
302  }
303 
304  // If the point is not yet in a cluster then we now add
305  if (!(neighborHit->getStatusBits() & reco::ClusterHit3D::CLUSTERATTACHED)) {
307  cluster.addHit3D(neighborHit);
308  }
309 
310  candPairList.pop_front();
311  }
312  }
313 
314  //------------------------------------------------------------------------------------------------------------------------------------------
315 
317 } // 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:330
#define DEFINE_ART_CLASS_TOOL(tool)
Definition: ToolMacros.h:42
kdTree class definiton
Definition: kdTree.h:31
bool m_enableMonitoring
Data members to follow.
The data type to uniquely identify a Plane.
Definition: geo_types.h:364
std::list< KdTreeNode > KdTreeNodeList
Definition: kdTree.h:69
Implements a kdTree for use in clustering.
size_t FindNearestNeighbors(const reco::ClusterHit3D *, const KdTreeNode &, CandPairList &, float &) const
Definition: kdTree.cxx:183
Labelled "noise" by a clustering algorithm.
Definition: Cluster3D.h:105
cout<< "Opened file "<< fin<< " ixs= "<< ixs<< endl;if(ixs==0) hhh=(TH1F *) fff-> Get("h1")
Definition: AddMC.C:8
Cluster finding and building.
IClusterAlg interface class definiton.
Definition: IClusterAlg.h:21
unsigned int getStatusBits() const
Definition: Cluster3D.h:154
define a kd tree node
Definition: kdTree.h:127
T get(std::string const &key) const
Definition: ParameterSet.h:314
TimeValues
enumerate the possible values for time checking if monitoring timing
Definition: IClusterAlg.h:49
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:326
This provides an art tool interface definition for 3D Cluster algorithms.
The data type to uniquely identify a TPC.
Definition: geo_types.h:306
std::unique_ptr< lar_cluster3d::IClusterParametersBuilder > m_clusterBuilder
Common cluster builder tool.
Detector simulation of raw signals on wires.
std::list< CandPair > CandPairList
Definition: kdTree.h:84
void Cluster3DHits(reco::HitPairList &hitPairList, reco::ClusterParametersList &clusterParametersList) const override
Given a set of recob hits, run DBscan to form 3D clusters.
Encapsulate the construction of a single detector plane .
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.
float getTimeToExecute() const
Definition: kdTree.h:104
"visited" by a clustering algorithm
Definition: Cluster3D.h:104
std::vector< float > m_timeVector
void put_or_replace(std::string const &key)
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:109
std::list< ClusterParameters > ClusterParametersList
Definition: Cluster3D.h:393
attached to a cluster
Definition: Cluster3D.h:106
void addHit3D(const reco::ClusterHit3D *hit3D)
Definition: Cluster3D.h:445
void setStatusBit(unsigned bits) const
Definition: Cluster3D.h:177