Classes | Public Types | Public Member Functions | Private Member Functions | Private Attributes | List of all members
lar_cluster3d::kdTree Class Reference

kdTree class definiton More...

#include <kdTree.h>

Classes

class  KdTreeNode
 define a kd tree node More...
 

Public Types

using KdTreeNodeVec = std::vector< KdTreeNode >
 
using KdTreeNodeList = std::list< KdTreeNode >
 
using Hit3DVec = std::vector< const reco::ClusterHit3D * >
 
using CandPair = std::pair< double, const reco::ClusterHit3D * >
 
using CandPairList = std::list< CandPair >
 

Public Member Functions

 kdTree ()
 Default Constructor. More...
 
 kdTree (fhicl::ParameterSet const &pset)
 Constructor. More...
 
 ~kdTree ()
 Destructor. More...
 
void configure (fhicl::ParameterSet const &pset)
 Configure our kdTree... More...
 
KdTreeNodeBuildKdTree (Hit3DVec::iterator, Hit3DVec::iterator, KdTreeNodeList &, int depth=0) const
 Given an input set of ClusterHit3D objects, build a kd tree structure. More...
 
size_t FindNearestNeighbors (const reco::ClusterHit3D *, const KdTreeNode &, CandPairList &, float &) const
 
bool FindEntry (const reco::ClusterHit3D *, const KdTreeNode &, CandPairList &, float &, bool &, int) const
 
bool FindEntryBrute (const reco::ClusterHit3D *, const KdTreeNode &, int) const
 
KdTreeNode BuildKdTree (const reco::HitPairList &, KdTreeNodeList &) const
 Given an input HitPairList, build out the map of nearest neighbors. More...
 
KdTreeNode BuildKdTree (const reco::HitPairListPtr &, KdTreeNodeList &) const
 Given an input HitPairListPtr, build out the map of nearest neighbors. More...
 
float getTimeToExecute () const
 

Private Member Functions

bool consistentPairs (const reco::ClusterHit3D *pair1, const reco::ClusterHit3D *pair2, float &hitSeparation) const
 The bigger question: are two pairs of hits consistent? More...
 
float DistanceBetweenNodes (const reco::ClusterHit3D *, const reco::ClusterHit3D *) const
 
float DistanceBetweenNodesYZ (const reco::ClusterHit3D *, const reco::ClusterHit3D *) const
 

Private Attributes

bool fEnableMonitoring
 
float fTimeToBuild
 
float fPairSigmaPeakTime
 Consider hits consistent if "significance" less than this. More...
 
float fRefLeafBestDist
 Set neighborhood distance to this when ref leaf found. More...
 
int fMaxWireDeltas
 Maximum total number of delta wires. More...
 

Detailed Description

kdTree class definiton

Definition at line 30 of file kdTree.h.

Member Typedef Documentation

using lar_cluster3d::kdTree::CandPair = std::pair<double,const reco::ClusterHit3D*>

Definition at line 78 of file kdTree.h.

Definition at line 79 of file kdTree.h.

Definition at line 68 of file kdTree.h.

Definition at line 67 of file kdTree.h.

Definition at line 66 of file kdTree.h.

Constructor & Destructor Documentation

lar_cluster3d::kdTree::kdTree ( )
inline

Default Constructor.

Definition at line 36 of file kdTree.h.

36  : fEnableMonitoring(false),
37  fTimeToBuild(0.),
39  fRefLeafBestDist(0.),
40  fMaxWireDeltas(0) {}
float fRefLeafBestDist
Set neighborhood distance to this when ref leaf found.
Definition: kdTree.h:110
float fPairSigmaPeakTime
Consider hits consistent if "significance" less than this.
Definition: kdTree.h:109
int fMaxWireDeltas
Maximum total number of delta wires.
Definition: kdTree.h:111
lar_cluster3d::kdTree::kdTree ( fhicl::ParameterSet const &  pset)

Constructor.

Parameters
pset

Definition at line 24 of file kdTree.cxx.

25 {
26  this->configure(pset);
27 }
void configure(fhicl::ParameterSet const &pset)
Configure our kdTree...
Definition: kdTree.cxx:37
lar_cluster3d::kdTree::~kdTree ( )

Destructor.

Definition at line 31 of file kdTree.cxx.

32 {
33 }

Member Function Documentation

kdTree::KdTreeNode & lar_cluster3d::kdTree::BuildKdTree ( Hit3DVec::iterator  first,
Hit3DVec::iterator  last,
KdTreeNodeList kdTreeNodeContainer,
int  depth = 0 
) const

Given an input set of ClusterHit3D objects, build a kd tree structure.

Parameters
hitPairListThe input list of 3D hits to run clustering on
kdTreeVecContainer for the nodes

Definition at line 112 of file kdTree.cxx.

116 {
117  // Ok, so if the input list is more than one element then we have work to do... but if less then handle end condition
118  if (std::distance(first,last) < 2)
119  {
120  if (first != last) kdTreeNodeContainer.emplace_back(*first);
121  else kdTreeNodeContainer.emplace_back(KdTreeNode());
122  }
123  // Otherwise we need to keep splitting...
124  else
125  {
126  // First task is to find "d" with the largest range. We need to find the min/max for the four dimensions
127  std::pair<Hit3DVec::iterator,Hit3DVec::iterator> minMaxXPair = std::minmax_element(first,last,[](const reco::ClusterHit3D* left, const reco::ClusterHit3D* right){return left->getPosition()[0] < right->getPosition()[0];});
128  std::pair<Hit3DVec::iterator,Hit3DVec::iterator> minMaxYPair = std::minmax_element(first,last,[](const reco::ClusterHit3D* left, const reco::ClusterHit3D* right){return left->getPosition()[1] < right->getPosition()[1];});
129  std::pair<Hit3DVec::iterator,Hit3DVec::iterator> minMaxZPair = std::minmax_element(first,last,[](const reco::ClusterHit3D* left, const reco::ClusterHit3D* right){return left->getPosition()[2] < right->getPosition()[2];});
130 
131  std::vector<float> rangeVec(3,0.);
132 
133  rangeVec[0] = (*minMaxXPair.second)->getPosition()[0] - (*minMaxXPair.first)->getPosition()[0];
134  rangeVec[1] = (*minMaxYPair.second)->getPosition()[1] - (*minMaxYPair.first)->getPosition()[1];
135  rangeVec[2] = (*minMaxZPair.second)->getPosition()[2] - (*minMaxZPair.first)->getPosition()[2];
136 
137  std::vector<float>::iterator maxRangeItr = std::max_element(rangeVec.begin(),rangeVec.end());
138 
139  size_t maxRangeIdx = std::distance(rangeVec.begin(),maxRangeItr);
140 
141  // Sort the list so we can do the split
142  std::sort(first,last,[maxRangeIdx](const auto& left, const auto& right){return left->getPosition()[maxRangeIdx] < right->getPosition()[maxRangeIdx];});
143 
144  size_t middleElem = std::distance(first,last) / 2;
145  Hit3DVec::iterator middleItr = first;
146 
147  std::advance(middleItr, middleElem);
148 
149  // Take care of the special case where the value of the median may be repeated so we actually want to make sure we point at the first occurence
150  if (std::distance(first,middleItr) > 1)
151  {
152  while(middleItr != first+1)
153  {
154  if (!((*(middleItr-1))->getPosition()[maxRangeIdx] < (*middleItr)->getPosition()[maxRangeIdx])) middleItr--;
155  else break;
156  }
157  }
158 
160  float axisVal = 0.5*((*middleItr)->getPosition()[maxRangeIdx] + (*(middleItr-1))->getPosition()[maxRangeIdx]);
161  KdTreeNode& leftNode = BuildKdTree(first, middleItr, kdTreeNodeContainer, depth+1);
162  KdTreeNode& rightNode = BuildKdTree(middleItr, last, kdTreeNodeContainer, depth+1);
163 
164  kdTreeNodeContainer.push_back(KdTreeNode(axis[maxRangeIdx],axisVal,leftNode,rightNode));
165  }
166 
167  return kdTreeNodeContainer.back();
168 }
intermediate_table::iterator iterator
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:158
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
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
kdTree::KdTreeNode lar_cluster3d::kdTree::BuildKdTree ( const reco::HitPairList hitPairList,
KdTreeNodeList kdTreeNodeContainer 
) const

Given an input HitPairList, build out the map of nearest neighbors.

Definition at line 50 of file kdTree.cxx.

52 {
53  // The first task is to build the kd tree
54  cet::cpu_timer theClockBuildNeighborhood;
55 
56  if (fEnableMonitoring) theClockBuildNeighborhood.start();
57 
58  // The input is a list and we need to copy to a vector so we can sort ranges
59  Hit3DVec hit3DVec;
60 
61  hit3DVec.reserve(hitPairList.size());
62 
63  for(const auto& hit : hitPairList) hit3DVec.emplace_back(&hit);
64 
65  KdTreeNode topNode = BuildKdTree(hit3DVec.begin(), hit3DVec.end(), kdTreeNodeContainer);
66 
68  {
69  theClockBuildNeighborhood.stop();
70  fTimeToBuild = theClockBuildNeighborhood.accumulated_real_time();
71  }
72 
73  return topNode;
74 }
std::vector< const reco::ClusterHit3D * > Hit3DVec
Definition: kdTree.h:68
Detector simulation of raw signals on wires.
double accumulated_real_time() const
Definition: cpu_timer.cc:66
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
void start()
Definition: cpu_timer.cc:83
kdTree::KdTreeNode lar_cluster3d::kdTree::BuildKdTree ( const reco::HitPairListPtr hitPairList,
KdTreeNodeList kdTreeNodeContainer 
) const

Given an input HitPairListPtr, build out the map of nearest neighbors.

Definition at line 77 of file kdTree.cxx.

79 {
80 
81  // The first task is to build the kd tree
82  cet::cpu_timer theClockBuildNeighborhood;
83 
84  if (fEnableMonitoring) theClockBuildNeighborhood.start();
85 
86  // The input is a list and we need to copy to a vector so we can sort ranges
87  //Hit3DVec hit3DVec{std::begin(hitPairList),std::end(hitPairList)};
88  Hit3DVec hit3DVec;
89 
90  hit3DVec.reserve(hitPairList.size());
91 
92  for(const auto& hit3D : hitPairList)
93  {
94  // Make sure all the bits used by the clustering stage have been cleared
96  for(const auto& hit2D : hit3D->getHits())
97  if (hit2D) hit2D->clearStatusBits(0xFFFFFFFF);
98  hit3DVec.emplace_back(hit3D);
99  }
100 
101  KdTreeNode topNode = BuildKdTree(hit3DVec.begin(), hit3DVec.end(), kdTreeNodeContainer);
102 
103  if (fEnableMonitoring)
104  {
105  theClockBuildNeighborhood.stop();
106  fTimeToBuild = theClockBuildNeighborhood.accumulated_real_time();
107  }
108 
109  return topNode;
110 }
Hit contains 2D hit from view 2 (w plane)
Definition: Cluster3D.h:116
Hit contains 2D hit from view 0 (u plane)
Definition: Cluster3D.h:114
std::vector< const reco::ClusterHit3D * > Hit3DVec
Definition: kdTree.h:68
Hit contains 2D hit from view 1 (v plane)
Definition: Cluster3D.h:115
double accumulated_real_time() const
Definition: cpu_timer.cc:66
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
void start()
Definition: cpu_timer.cc:83
void lar_cluster3d::kdTree::configure ( fhicl::ParameterSet const &  pset)

Configure our kdTree...

Parameters
ParameterSetThe input set of parameters for configuration

Definition at line 37 of file kdTree.cxx.

38 {
39  fEnableMonitoring = pset.get<bool> ("EnableMonitoring", true);
40  fPairSigmaPeakTime = pset.get<float>("PairSigmaPeakTime", 3. );
41  fRefLeafBestDist = pset.get<float>("RefLeafBestDist", 0.5 );
42  fMaxWireDeltas = pset.get<int> ("MaxWireDeltas", 3 );
43 
44  fTimeToBuild = 0;
45 
46  return;
47 }
float fRefLeafBestDist
Set neighborhood distance to this when ref leaf found.
Definition: kdTree.h:110
float fPairSigmaPeakTime
Consider hits consistent if "significance" less than this.
Definition: kdTree.h:109
int fMaxWireDeltas
Maximum total number of delta wires.
Definition: kdTree.h:111
bool lar_cluster3d::kdTree::consistentPairs ( const reco::ClusterHit3D pair1,
const reco::ClusterHit3D pair2,
float &  hitSeparation 
) const
private

The bigger question: are two pairs of hits consistent?

Definition at line 272 of file kdTree.cxx.

273 {
274  // Strategy: We consider comparing "hit pairs" which may consist of 2 or 3 actual hits.
275  // Also, if only pairs, they can be U-V, U-W or V-W so we can't assume which views we have
276  // So do a simplified comparison:
277  // 1) compare the pair times and require "overlap" (in the sense of hit pair production)
278  // 2) look at distance between pairs in each of the wire directions
279 
280  bool consistent(false);
281 
282  if (bestDist < std::numeric_limits<float>::max() && pair1->getWireIDs()[0].Cryostat == pair2->getWireIDs()[0].Cryostat && pair1->getWireIDs()[0].TPC == pair2->getWireIDs()[0].TPC)
283  {
284  // Loose constraint to weed out the obviously bad combinations
285  // So this is not strictly correct but is close enough and should save computation time...
286  if (std::fabs(pair1->getAvePeakTime() - pair2->getAvePeakTime()) < fPairSigmaPeakTime * (pair1->getSigmaPeakTime() + pair2->getSigmaPeakTime()))
287  {
288  int wireDeltas[] = {0, 0, 0};
289 
290  // Now go through the hits and compare view by view to look for delta wire and tigher constraint on delta t
291  for(size_t idx = 0; idx < 3; idx++)
292  wireDeltas[idx] = std::abs(int(pair1->getWireIDs()[idx].Wire) - int(pair2->getWireIDs()[idx].Wire));
293 
294  // put wire deltas in order...
295  std::sort(wireDeltas, wireDeltas + 3);
296 
297  // Requirement to be considered a nearest neighbor
298  if (wireDeltas[2] < 3)
299  {
300  float hitSeparation = std::max(float(0.0001),DistanceBetweenNodesYZ(pair1,pair2));
301 
302  // Final cut...
303  if (hitSeparation < bestDist)
304  {
305  bestDist = hitSeparation;
306  consistent = true;
307  }
308  }
309  }
310  }
311 
312  return consistent;
313 }
float getSigmaPeakTime() const
Definition: Cluster3D.h:165
float getAvePeakTime() const
Definition: Cluster3D.h:163
T abs(T value)
static int max(int a, int b)
float DistanceBetweenNodesYZ(const reco::ClusterHit3D *, const reco::ClusterHit3D *) const
Definition: kdTree.cxx:316
float fPairSigmaPeakTime
Consider hits consistent if "significance" less than this.
Definition: kdTree.h:109
const std::vector< geo::WireID > & getWireIDs() const
Definition: Cluster3D.h:173
float lar_cluster3d::kdTree::DistanceBetweenNodes ( const reco::ClusterHit3D node1,
const reco::ClusterHit3D node2 
) const
private

Definition at line 327 of file kdTree.cxx.

328 {
329  const Eigen::Vector3f& node1Pos = node1->getPosition();
330  const Eigen::Vector3f& node2Pos = node2->getPosition();
331  float deltaNode[] = {node1Pos[0]-node2Pos[0], node1Pos[1]-node2Pos[1], node1Pos[2]-node2Pos[2]};
332  float yzDist2 = deltaNode[1]*deltaNode[1] + deltaNode[2]*deltaNode[2];
333  float xDist2 = deltaNode[0]*deltaNode[0];
334 
335  // Standard euclidean distance
336  return std::sqrt(xDist2 + yzDist2);
337 
338  // Manhatten distance
339  //return std::fabs(deltaNode[0]) + std::fabs(deltaNode[1]) + std::fabs(deltaNode[2]);
340  /*
341  // Chebyshev distance
342  // We look for maximum distance by wires...
343 
344  // Now go through the hits and compare view by view to look for delta wire and tigher constraint on delta t
345  int wireDeltas[] = {0,0,0};
346 
347  for(size_t idx = 0; idx < 3; idx++)
348  wireDeltas[idx] = std::abs(int(node1->getWireIDs()[idx].Wire) - int(node2->getWireIDs()[idx].Wire));
349 
350  // put wire deltas in order...
351  std::sort(wireDeltas, wireDeltas + 3);
352 
353  return std::sqrt(deltaNode[0]*deltaNode[0] + 0.09 * float(wireDeltas[2]*wireDeltas[2]));
354  */
355 }
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:158
float lar_cluster3d::kdTree::DistanceBetweenNodesYZ ( const reco::ClusterHit3D node1,
const reco::ClusterHit3D node2 
) const
private

Definition at line 316 of file kdTree.cxx.

317 {
318  const Eigen::Vector3f& node1Pos = node1->getPosition();
319  const Eigen::Vector3f& node2Pos = node2->getPosition();
320  float deltaNode[] = {node1Pos[0]-node2Pos[0], node1Pos[1]-node2Pos[1], node1Pos[2]-node2Pos[2]};
321  float yzDist2 = deltaNode[1]*deltaNode[1] + deltaNode[2]*deltaNode[2];
322 
323  // Standard euclidean distance
324  return std::sqrt(yzDist2);
325 }
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:158
bool lar_cluster3d::kdTree::FindEntry ( const reco::ClusterHit3D refHit,
const KdTreeNode node,
CandPairList CandPairList,
float &  bestDist,
bool selfNotFound,
int  depth 
) const

Definition at line 207 of file kdTree.cxx.

208 {
209  bool foundEntry(false);
210 
211  // If at a leaf then time to decide to add hit or not
212  if (node.isLeafNode())
213  {
214  float hitSeparation(0.);
215 
216  // Is this the droid we are looking for?
217  if (refHit == node.getClusterHit3D()) selfNotFound = false;
218 
219  // This is the tight constraint on the hits
220  if (consistentPairs(refHit, node.getClusterHit3D(), hitSeparation))
221  {
222  CandPairList.emplace_back(hitSeparation,node.getClusterHit3D());
223 
224  if (bestDist < std::numeric_limits<float>::max()) bestDist = std::max(bestDist,hitSeparation);
225  else bestDist = std::max(float(0.5),hitSeparation);
226  }
227 
228  foundEntry = !selfNotFound;
229  }
230  // Otherwise we need to keep searching
231  else
232  {
233  float refPosition = refHit->getPosition()[node.getSplitAxis()];
234 
235  if (refPosition < node.getAxisValue())
236  {
237  foundEntry = FindEntry(refHit, node.leftTree(), CandPairList, bestDist, selfNotFound, depth+1);
238 
239  if (!foundEntry && refPosition + bestDist > node.getAxisValue()) foundEntry = FindEntry(refHit, node.rightTree(), CandPairList, bestDist, selfNotFound, depth+1);
240  }
241  else
242  {
243  foundEntry = FindEntry(refHit, node.rightTree(), CandPairList, bestDist, selfNotFound, depth+1);
244 
245  if (!foundEntry && refPosition - bestDist < node.getAxisValue()) foundEntry = FindEntry(refHit, node.leftTree(), CandPairList, bestDist, selfNotFound, depth+1);
246  }
247  }
248 
249  return foundEntry;
250 }
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:158
static int max(int a, int b)
bool consistentPairs(const reco::ClusterHit3D *pair1, const reco::ClusterHit3D *pair2, float &hitSeparation) const
The bigger question: are two pairs of hits consistent?
Definition: kdTree.cxx:272
std::list< CandPair > CandPairList
Definition: kdTree.h:79
bool FindEntry(const reco::ClusterHit3D *, const KdTreeNode &, CandPairList &, float &, bool &, int) const
Definition: kdTree.cxx:207
bool lar_cluster3d::kdTree::FindEntryBrute ( const reco::ClusterHit3D refHit,
const KdTreeNode node,
int  depth 
) const

Definition at line 252 of file kdTree.cxx.

253 {
254  // If at a leaf then time to decide to add hit or not
255  if (node.isLeafNode())
256  {
257  // This is the tight constraint on the hits
258  if (refHit == node.getClusterHit3D()) return true;
259  }
260  // Otherwise we need to keep searching
261  else
262  {
263  if (FindEntryBrute(refHit, node.leftTree(), depth+1)) return true;
264  if (FindEntryBrute(refHit, node.rightTree(), depth+1)) return true;
265  }
266 
267  return false;
268 }
bool FindEntryBrute(const reco::ClusterHit3D *, const KdTreeNode &, int) const
Definition: kdTree.cxx:252
size_t lar_cluster3d::kdTree::FindNearestNeighbors ( const reco::ClusterHit3D refHit,
const KdTreeNode node,
CandPairList CandPairList,
float &  bestDist 
) const

Definition at line 170 of file kdTree.cxx.

171 {
172  // If at a leaf then time to decide to add hit or not
173  if (node.isLeafNode())
174  {
175  // Is this the droid we are looking for?
176  if (refHit == node.getClusterHit3D()) bestDist = fRefLeafBestDist; // This distance will grab neighbors with delta wire # = 1 in all three planes
177  // This is the tight constraint on the hits
178  else if (consistentPairs(refHit, node.getClusterHit3D(), bestDist))
179  {
180  CandPairList.emplace_back(bestDist,node.getClusterHit3D());
181 
182  bestDist = std::max(fRefLeafBestDist, bestDist); // This insures we will always consider neighbors with wire # changing in 2 planes
183  }
184  }
185  // Otherwise we need to keep searching
186  else
187  {
188  float refPosition = refHit->getPosition()[node.getSplitAxis()];
189 
190  if (refPosition < node.getAxisValue())
191  {
192  FindNearestNeighbors(refHit, node.leftTree(), CandPairList, bestDist);
193 
194  if (refPosition + bestDist > node.getAxisValue()) FindNearestNeighbors(refHit, node.rightTree(), CandPairList, bestDist);
195  }
196  else
197  {
198  FindNearestNeighbors(refHit, node.rightTree(), CandPairList, bestDist);
199 
200  if (refPosition - bestDist < node.getAxisValue()) FindNearestNeighbors(refHit, node.leftTree(), CandPairList, bestDist);
201  }
202  }
203 
204  return CandPairList.size();
205 }
float fRefLeafBestDist
Set neighborhood distance to this when ref leaf found.
Definition: kdTree.h:110
const Eigen::Vector3f getPosition() const
Definition: Cluster3D.h:158
size_t FindNearestNeighbors(const reco::ClusterHit3D *, const KdTreeNode &, CandPairList &, float &) const
Definition: kdTree.cxx:170
static int max(int a, int b)
bool consistentPairs(const reco::ClusterHit3D *pair1, const reco::ClusterHit3D *pair2, float &hitSeparation) const
The bigger question: are two pairs of hits consistent?
Definition: kdTree.cxx:272
std::list< CandPair > CandPairList
Definition: kdTree.h:79
float lar_cluster3d::kdTree::getTimeToExecute ( ) const
inline

Definition at line 95 of file kdTree.h.

95 {return fTimeToBuild;}

Member Data Documentation

bool lar_cluster3d::kdTree::fEnableMonitoring
private

Definition at line 107 of file kdTree.h.

int lar_cluster3d::kdTree::fMaxWireDeltas
private

Maximum total number of delta wires.

Definition at line 111 of file kdTree.h.

float lar_cluster3d::kdTree::fPairSigmaPeakTime
private

Consider hits consistent if "significance" less than this.

Definition at line 109 of file kdTree.h.

float lar_cluster3d::kdTree::fRefLeafBestDist
private

Set neighborhood distance to this when ref leaf found.

Definition at line 110 of file kdTree.h.

float lar_cluster3d::kdTree::fTimeToBuild
mutableprivate

Definition at line 108 of file kdTree.h.


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