CMS 3D CMS Logo

KDTreeLinkerAlgo.h
Go to the documentation of this file.
1 #ifndef KDTreeLinkerAlgoTemplated_h
2 #define KDTreeLinkerAlgoTemplated_h
3 
4 #include <cassert>
5 #include <vector>
6 #include <array>
7 #include <algorithm>
8 
9 // Box structure used to define 2D field.
10 // It's used in KDTree building step to divide the detector
11 // space (ECAL, HCAL...) and in searching step to create a bounding
12 // box around the demanded point (Track collision point, PS projection...).
13 template <unsigned DIM = 2>
14 struct KDTreeBox {
15  std::array<float, DIM> dimmin, dimmax;
16 
17  template <typename... Ts>
18  KDTreeBox(Ts... dimargs) {
19  static_assert(sizeof...(dimargs) == 2 * DIM, "Constructor requires 2*DIM args");
20  std::vector<float> dims = {dimargs...};
21  for (unsigned i = 0; i < DIM; ++i) {
22  dimmin[i] = dims[2 * i];
23  dimmax[i] = dims[2 * i + 1];
24  }
25  }
26 
27  KDTreeBox() {}
28 };
29 
30 // Data stored in each KDTree node.
31 // The dim1/dim2 fields are usually the duplication of some PFRecHit values
32 // (eta/phi or x/y). But in some situations, phi field is shifted by +-2.Pi
33 template <typename DATA, unsigned DIM = 2>
36  std::array<float, DIM> dims;
37 
38 public:
40 
41  template <typename... Ts>
42  KDTreeNodeInfo(const DATA &d, Ts... dimargs) : data(d), dims{{dimargs...}} {}
43  template <typename... Ts>
44  bool operator>(const KDTreeNodeInfo &rhs) const {
45  return (data > rhs.data);
46  }
47 };
48 
49 template <typename DATA, unsigned DIM = 2>
50 struct KDTreeNodes {
51  std::array<std::vector<float>, DIM> dims;
52  std::vector<int> right;
53  std::vector<DATA> data;
54 
55  int poolSize;
56  int poolPos;
57 
58  constexpr KDTreeNodes() : poolSize(-1), poolPos(-1) {}
59 
60  bool empty() const { return poolPos == -1; }
61  int size() const { return poolPos + 1; }
62 
63  void clear() {
64  for (auto &dim : dims) {
65  dim.clear();
66  }
67  right.clear();
68  data.clear();
69  poolSize = -1;
70  poolPos = -1;
71  }
72 
73  int getNextNode() {
74  ++poolPos;
75  return poolPos;
76  }
77 
78  void build(int sizeData) {
79  poolSize = sizeData * 2 - 1;
80  for (auto &dim : dims) {
81  dim.resize(poolSize);
82  }
83  right.resize(poolSize);
84  data.resize(poolSize);
85  };
86 
87  constexpr bool isLeaf(int right) const {
88  // Valid values of right are always >= 2
89  // index 0 is the root, and 1 is the first left node
90  // Exploit index values 0 and 1 to mark which of dim1/dim2 is the
91  // current one in recSearch() at the depth of the leaf.
92  return right < 2;
93  }
94 
95  bool isLeafIndex(int index) const { return isLeaf(right[index]); }
96 };
97 
98 // Class that implements the KDTree partition of 2D space and
99 // a closest point search algorithme.
100 
101 template <typename DATA, unsigned int DIM = 2>
103 public:
104  // Dtor calls clear()
106 
107  // Here we build the KD tree from the "eltList" in the space define by "region".
108  void build(std::vector<KDTreeNodeInfo<DATA, DIM> > &eltList, const KDTreeBox<DIM> &region);
109 
110  // Here we search in the KDTree for all points that would be
111  // contained in the given searchbox. The founded points are stored in resRecHitList.
112  void search(const KDTreeBox<DIM> &searchBox, std::vector<DATA> &resRecHitList);
113 
114  // This reurns true if the tree is empty
115  bool empty() { return nodePool_.empty(); }
116 
117  // This returns the number of nodes + leaves in the tree
118  // (nElements should be (size() +1)/2)
119  int size() { return nodePool_.size(); }
120 
121  // This method clears all allocated structures.
122  void clear() { clearTree(); }
123 
124 private:
125  // The node pool allow us to do just 1 call to new for each tree building.
127 
128  std::vector<DATA> *closestNeighbour;
129  std::vector<KDTreeNodeInfo<DATA, DIM> > *initialEltList;
130 
131  //Fast median search with Wirth algorithm in eltList between low and high indexes.
132  int medianSearch(int low, int high, int treeDepth) const;
133 
134  // Recursif kdtree builder. Is called by build()
135  int recBuild(int low, int hight, int depth);
136 
137  // Recursif kdtree search. Is called by search()
138  void recSearch(int current, const KDTreeBox<DIM> &trackBox, int depth = 0) const;
139 
140  // This method frees the KDTree.
141  void clearTree() { nodePool_.clear(); }
142 };
143 
144 //Implementation
145 
146 template <typename DATA, unsigned int DIM>
148  const KDTreeBox<DIM> &region) {
149  if (!eltList.empty()) {
150  initialEltList = &eltList;
151 
152  size_t size = initialEltList->size();
153  nodePool_.build(size);
154 
155  // Here we build the KDTree
156  int root = recBuild(0, size, 0);
157  assert(root == 0);
158 
159  initialEltList = nullptr;
160  }
161 }
162 
163 //Fast median search with Wirth algorithm in eltList between low and high indexes.
164 template <typename DATA, unsigned int DIM>
165 int KDTreeLinkerAlgo<DATA, DIM>::medianSearch(int low, int high, int treeDepth) const {
166  int nbrElts = high - low;
167  int median = (nbrElts & 1) ? nbrElts / 2 : nbrElts / 2 - 1;
168  median += low;
169 
170  int l = low;
171  int m = high - 1;
172 
173  while (l < m) {
174  KDTreeNodeInfo<DATA, DIM> elt = (*initialEltList)[median];
175  int i = l;
176  int j = m;
177 
178  do {
179  // The even depth is associated to dim1 dimension
180  // The odd one to dim2 dimension
181  const unsigned thedim = treeDepth % DIM;
182  while ((*initialEltList)[i].dims[thedim] < elt.dims[thedim])
183  ++i;
184  while ((*initialEltList)[j].dims[thedim] > elt.dims[thedim])
185  --j;
186 
187  if (i <= j) {
188  std::swap((*initialEltList)[i], (*initialEltList)[j]);
189  i++;
190  j--;
191  }
192  } while (i <= j);
193  if (j < median)
194  l = i;
195  if (i > median)
196  m = j;
197  }
198 
199  return median;
200 }
201 
202 template <typename DATA, unsigned int DIM>
203 void KDTreeLinkerAlgo<DATA, DIM>::search(const KDTreeBox<DIM> &trackBox, std::vector<DATA> &recHits) {
204  if (!empty()) {
205  closestNeighbour = &recHits;
206  recSearch(0, trackBox, 0);
207  closestNeighbour = nullptr;
208  }
209 }
210 
211 template <typename DATA, unsigned int DIM>
212 void KDTreeLinkerAlgo<DATA, DIM>::recSearch(int current, const KDTreeBox<DIM> &trackBox, int depth) const {
213  // Iterate until leaf is found, or there are no children in the
214  // search window. If search has to proceed on both children, proceed
215  // the search to left child via recursion. Swap search window
216  // dimension on alternate levels.
217  while (true) {
218  const int dimIndex = depth % DIM;
219  int right = nodePool_.right[current];
220  if (nodePool_.isLeaf(right)) {
221  // If point inside the rectangle/area
222  // Use intentionally bit-wise & instead of logical && for better
223  // performance. It is faster to always do all comparisons than to
224  // allow use of branches to not do some if any of the first ones
225  // is false.
226  bool isInside = true;
227  for (unsigned i = 0; i < DIM; ++i) {
228  float dimCurr = nodePool_.dims[i][current];
229  isInside *= (dimCurr >= trackBox.dimmin[i]) & (dimCurr <= trackBox.dimmax[i]);
230  }
231  if (isInside) {
232  closestNeighbour->push_back(nodePool_.data[current]);
233  }
234  break;
235  } else {
236  float median = nodePool_.dims[dimIndex][current];
237 
238  bool goLeft = (trackBox.dimmin[dimIndex] <= median);
239  bool goRight = (trackBox.dimmax[dimIndex] >= median);
240 
241  ++depth;
242  if (goLeft & goRight) {
243  int left = current + 1;
244  recSearch(left, trackBox, depth);
245  // continue with right
246  current = right;
247  } else if (goLeft) {
248  ++current;
249  } else if (goRight) {
250  current = right;
251  } else {
252  break;
253  }
254  }
255  }
256 }
257 
258 template <typename DATA, unsigned int DIM>
260  int portionSize = high - low;
261 
262  if (portionSize == 1) { // Leaf case
263  int leaf = nodePool_.getNextNode();
264  const KDTreeNodeInfo<DATA, DIM> &info = (*initialEltList)[low];
265  nodePool_.right[leaf] = 0;
266  for (unsigned i = 0; i < DIM; ++i) {
267  nodePool_.dims[i][leaf] = info.dims[i];
268  }
269  nodePool_.data[leaf] = info.data;
270  return leaf;
271 
272  } else { // Node case
273 
274  // The even depth is associated to dim1 dimension
275  // The odd one to dim2 dimension
276  int medianId = medianSearch(low, high, depth);
277  int dimIndex = depth % DIM;
278  float medianVal = (*initialEltList)[medianId].dims[dimIndex];
279 
280  // We create the node
281  int nodeInd = nodePool_.getNextNode();
282 
283  ++depth;
284  ++medianId;
285 
286  // We recursively build the son nodes
287  int left = recBuild(low, medianId, depth);
288  assert(nodeInd + 1 == left);
289  int right = recBuild(medianId, high, depth);
290  nodePool_.right[nodeInd] = right;
291 
292  nodePool_.dims[dimIndex][nodeInd] = medianVal;
293 
294  return nodeInd;
295  }
296 }
297 
298 #endif
mps_fire.i
i
Definition: mps_fire.py:355
KDTreeNodes::size
int size() const
Definition: KDTreeLinkerAlgo.h:61
KDTreeNodes::isLeaf
constexpr bool isLeaf(int right) const
Definition: KDTreeLinkerAlgo.h:87
KDTreeLinkerAlgo::empty
bool empty()
Definition: KDTreeLinkerAlgo.h:115
KDTreeNodes::isLeafIndex
bool isLeafIndex(int index) const
Definition: KDTreeLinkerAlgo.h:95
KDTreeNodes::getNextNode
int getNextNode()
Definition: KDTreeLinkerAlgo.h:73
KDTreeLinkerAlgo::size
int size()
Definition: KDTreeLinkerAlgo.h:119
KDTreeNodeInfo::operator>
bool operator>(const KDTreeNodeInfo &rhs) const
Definition: KDTreeLinkerAlgo.h:44
KDTreeLinkerAlgo::~KDTreeLinkerAlgo
~KDTreeLinkerAlgo()
Definition: KDTreeLinkerAlgo.h:105
cms::cuda::assert
assert(be >=bs)
info
static const TGPicture * info(bool iBackgroundIsBlack)
Definition: FWCollectionSummaryWidget.cc:152
KDTreeNodes::KDTreeNodes
constexpr KDTreeNodes()
Definition: KDTreeLinkerAlgo.h:58
KDTreeBox::dimmin
std::array< float, DIM > dimmin
Definition: KDTreeLinkerAlgo.h:15
DIM
#define DIM(a)
Definition: LogEleMapdb.h:14738
KDTreeNodeInfo::KDTreeNodeInfo
KDTreeNodeInfo()
Definition: KDTreeLinkerAlgo.h:39
KDTreeLinkerAlgo::clearTree
void clearTree()
Definition: KDTreeLinkerAlgo.h:141
KDTreeLinkerAlgo::nodePool_
KDTreeNodes< DATA, DIM > nodePool_
Definition: KDTreeLinkerAlgo.h:126
KDTreeLinkerAlgo::search
void search(const KDTreeBox< DIM > &searchBox, std::vector< DATA > &resRecHitList)
Definition: KDTreeLinkerAlgo.h:203
std::swap
void swap(edm::DataFrameContainer &lhs, edm::DataFrameContainer &rhs)
Definition: DataFrameContainer.h:209
KDTreeBox::KDTreeBox
KDTreeBox(Ts... dimargs)
Definition: KDTreeLinkerAlgo.h:18
visualization-live-secondInstance_cfg.m
m
Definition: visualization-live-secondInstance_cfg.py:72
KDTreeNodes::dims
std::array< std::vector< float >, DIM > dims
Definition: KDTreeLinkerAlgo.h:51
KDTreeNodeInfo::KDTreeNodeInfo
KDTreeNodeInfo(const DATA &d, Ts... dimargs)
Definition: KDTreeLinkerAlgo.h:42
KDTreeLinkerAlgo::recBuild
int recBuild(int low, int hight, int depth)
Definition: KDTreeLinkerAlgo.h:259
KDTreeBox
Definition: KDTreeLinkerAlgo.h:14
KDTreeLinkerAlgo
Definition: KDTreeLinkerAlgo.h:102
KDTreeNodes::right
std::vector< int > right
Definition: KDTreeLinkerAlgo.h:52
KDTreeNodeInfo::data
DATA data
Definition: KDTreeLinkerAlgo.h:35
KDTreeNodeInfo::dims
std::array< float, DIM > dims
Definition: KDTreeLinkerAlgo.h:36
LEDCalibrationChannels.depth
depth
Definition: LEDCalibrationChannels.py:65
FastTrackerRecHitMaskProducer_cfi.recHits
recHits
Definition: FastTrackerRecHitMaskProducer_cfi.py:8
cscdqm::DATA
Definition: CSCDQM_Summary.h:47
KDTreeLinkerAlgo::initialEltList
std::vector< KDTreeNodeInfo< DATA, DIM > > * initialEltList
Definition: KDTreeLinkerAlgo.h:129
pfParticleNetPreprocessParams_cfi.median
median
Definition: pfParticleNetPreprocessParams_cfi.py:16
KDTreeBox::KDTreeBox
KDTreeBox()
Definition: KDTreeLinkerAlgo.h:27
root
Definition: RooFitFunction.h:10
KDTreeNodes::poolSize
int poolSize
Definition: KDTreeLinkerAlgo.h:55
KDTreeNodes::clear
void clear()
Definition: KDTreeLinkerAlgo.h:63
KDTreeNodeInfo
Definition: KDTreeLinkerAlgo.h:34
cmsLHEtoEOSManager.l
l
Definition: cmsLHEtoEOSManager.py:193
KDTreeLinkerAlgo::recSearch
void recSearch(int current, const KDTreeBox< DIM > &trackBox, int depth=0) const
Definition: KDTreeLinkerAlgo.h:212
KDTreeNodes::data
std::vector< DATA > data
Definition: KDTreeLinkerAlgo.h:53
LaserClient_cfi.high
high
Definition: LaserClient_cfi.py:50
KDTreeLinkerAlgo::clear
void clear()
Definition: KDTreeLinkerAlgo.h:122
KDTreeNodes::build
void build(int sizeData)
Definition: KDTreeLinkerAlgo.h:78
KDTreeBox::dimmax
std::array< float, DIM > dimmax
Definition: KDTreeLinkerAlgo.h:15
relativeConstraints.empty
bool empty
Definition: relativeConstraints.py:46
KDTreeNodes::empty
bool empty() const
Definition: KDTreeLinkerAlgo.h:60
HLT_2018_cff.region
region
Definition: HLT_2018_cff.py:81479
KDTreeLinkerAlgo::medianSearch
int medianSearch(int low, int high, int treeDepth) const
Definition: KDTreeLinkerAlgo.h:165
AlignmentPI::index
index
Definition: AlignmentPayloadInspectorHelper.h:46
KDTreeLinkerAlgo::build
void build(std::vector< KDTreeNodeInfo< DATA, DIM > > &eltList, const KDTreeBox< DIM > &region)
Definition: KDTreeLinkerAlgo.h:147
ztail.d
d
Definition: ztail.py:151
dqmiolumiharvest.j
j
Definition: dqmiolumiharvest.py:66
KDTreeNodes
Definition: KDTreeLinkerAlgo.h:50
KDTreeLinkerAlgo::closestNeighbour
std::vector< DATA > * closestNeighbour
Definition: KDTreeLinkerAlgo.h:128
LaserClient_cfi.low
low
Definition: LaserClient_cfi.py:52
KDTreeNodes::poolPos
int poolPos
Definition: KDTreeLinkerAlgo.h:56
findQualityFiles.size
size
Write out results.
Definition: findQualityFiles.py:443