Belle II Software  release-05-02-19
QuadTreeProcessor.h
1 /**************************************************************************
2 * BASF2 (Belle Analysis Framework 2) *
3 * Copyright(C) 2014 - Belle II Collaboration *
4 * *
5 * Author: The Belle II Collaboration *
6 * Contributors: Viktor Trusov, Thomas Hauth, Nils Braun *
7 * *
8 * This software is provided "as is" without any warranty. *
9 **************************************************************************/
10 #pragma once
11 
12 #include <tracking/trackFindingCDC/legendre/quadtree/QuadTreeNode.h>
13 #include <tracking/trackFindingCDC/legendre/quadtree/QuadTreeItem.h>
14 
15 #include <tracking/trackFindingCDC/utilities/Algorithms.h>
16 
17 #include <algorithm>
18 #include <functional>
19 #include <memory>
20 #include <map>
21 #include <vector>
22 #include <deque>
23 #include <utility>
24 
25 namespace Belle2 {
30  namespace TrackFindingCDC {
31 
38  template<typename AX, typename AY, class AData>
39  class QuadTreeProcessor {
40 
41  public:
43  using Item = QuadTreeItem<AData>;
44 
46  using QuadTree = QuadTreeNode<AX, AY, Item>;
47 
49  using XSpan = typename QuadTree::XSpan;
50 
52  using YSpan = typename QuadTree::YSpan;
53 
55  using XYSpans = std::pair<XSpan, YSpan>;
56 
58  using QuadTreeChildren = typename QuadTree::Children;
59 
61  using CandidateReceiver = std::function<void(const std::vector<AData*>&, QuadTree*)>;
62 
63  public:
70  QuadTreeProcessor(int lastLevel,
71  int seedLevel,
72  const XYSpans& xySpans,
73  bool debugOutput = false)
74  : m_quadTree{std::make_unique<QuadTree>(xySpans.first, xySpans.second, 0, nullptr)}
75  , m_lastLevel(lastLevel)
76  , m_seedLevel(seedLevel)
77  , m_debugOutput(debugOutput)
79  {
80  }
81 
85  virtual ~QuadTreeProcessor()
86  {
87  clear();
88  }
89 
93  void clear()
94  {
95  m_seededTrees.clear();
96  m_quadTree->clearChildren();
97  m_quadTree->clearItems();
98  m_items.clear();
99  }
100 
104  void seed(std::vector<AData*>& datas)
105  {
106  // Create the items
107  for (AData* data : datas) {
108  m_items.emplace_back(data);
109  }
110 
111  // Creating the seed level
112  long nSeedBins = pow(2, m_seedLevel);
113  m_seededTrees.reserve(nSeedBins * nSeedBins);
114 
115  // Expand the first levels to the seed sectors
116  m_seededTrees.push_back(m_quadTree.get());
117  std::vector<QuadTree*> nextSeededTrees;
118 
119  for (int level = 0; level < m_seedLevel; ++level) {
120  for (QuadTree* node : m_seededTrees) {
121  if (node->getChildren().empty()) {
122  this->createChildren(node, node->getChildren());
123  }
124  for (QuadTree& child : node->getChildren()) {
125  nextSeededTrees.push_back(&child);
126  }
127  }
128  std::swap(nextSeededTrees, m_seededTrees);
129  nextSeededTrees.clear();
130  }
131 
132  // Fill the seed level with the items
133  for (QuadTree* seededTree : m_seededTrees) {
134  seededTree->reserveItems(m_items.size());
135 
136  for (Item& item : m_items) {
137  if (item.isUsed()) continue;
138  if (isInNode(seededTree, item.getPointer())) {
139  seededTree->insertItem(&item);
140  }
141  }
142  }
143  }
144 
145  public:
150  std::vector<AData*> getAssignedItems()
151  {
152  std::vector<const CDCWireHit*> result;
153  for (QuadTree* seededTree : m_seededTrees) {
154  for (Item* item : seededTree->getItems()) {
155  result.push_back(item->getPointer());
156  }
157  }
158  std::sort(result.begin(), result.end());
159  result.erase(std::unique(result.begin(), result.end()), result.end());
160  return result;
161  }
162 
163  public:
169  void fill(const CandidateReceiver& candidateReceiver, int nHitsThreshold)
170  {
171  fill(candidateReceiver, nHitsThreshold, std::numeric_limits<AY>::max());
172  }
173 
180  void fill(const CandidateReceiver& candidateReceiver, int nHitsThreshold, float yLimit)
181  {
182  std::vector<QuadTree*> quadTrees = m_seededTrees;
183  std::sort(quadTrees.begin(), quadTrees.end(), [](QuadTree * quadTree1, QuadTree * quadTree2) {
184  return quadTree1->getNItems() > quadTree2->getNItems();
185  });
186 
187  for (QuadTree* tree : quadTrees) {
188  erase_remove_if(tree->getItems(), [](Item * hit) { return hit->isUsed(); });
189  fillGivenTree(tree, candidateReceiver, nHitsThreshold, yLimit);
190  }
191  }
192 
193  private:
198  void fillGivenTree(QuadTree* node,
199  const CandidateReceiver& candidateReceiver,
200  int nItemsThreshold,
201  AY yLimit)
202  {
203  if (node->getNItems() < nItemsThreshold) {
204  return;
205  }
206 
207  if ((node->getYMin() > yLimit) or (-node->getYMax() > yLimit)) {
208  return;
209  }
210 
211  if (isLeaf(node)) {
212  callResultFunction(node, candidateReceiver);
213  return;
214  }
215 
216  if (node->getChildren().empty()) {
217  this->createChildren(node, node->getChildren());
218  }
219 
220  if (!node->checkFilled()) {
221  fillChildren(node, node->getItems());
222  node->setFilled();
223  }
224 
225  std::vector<QuadTree*> children;
226  for (QuadTree& child : node->getChildren()) {
227  children.push_back(&child);
228  }
229  const auto compareNItems = [](const QuadTree * lhs, const QuadTree * rhs) {
230  return lhs->getNItems() < rhs->getNItems();
231  };
232 
233  // Explicitly count down the children
234  const int nChildren = children.size();
235  for (int iChild = 0; iChild < nChildren; ++iChild) {
236  auto itHeaviestChild = std::max_element(children.begin(), children.end(), compareNItems);
237  QuadTree* heaviestChild = *itHeaviestChild;
238  children.erase(itHeaviestChild);
239  // After we have processed some children we need to get rid of the already used hits in all the children,
240  // because this can change the number of items drastically
241  erase_remove_if(heaviestChild->getItems(), [&](Item * hit) { return hit->isUsed(); });
242  this->fillGivenTree(heaviestChild, candidateReceiver, nItemsThreshold, yLimit);
243  }
244  }
245 
250  void createChildren(QuadTree* node, QuadTreeChildren& m_children) const
251  {
252  for (int i = 0; i < node->getXNbins(); ++i) {
253  for (int j = 0; j < node->getYNbins(); ++j) {
254  const XYSpans& xySpans = createChild(node, i, j);
255  const XSpan& xSpan = xySpans.first;
256  const YSpan& ySpan = xySpans.second;
257  m_children.push_back(QuadTree(xSpan, ySpan, node->getLevel() + 1, node));
258  }
259  }
260  }
261 
266  void fillChildren(QuadTree* node, std::vector<Item*>& items)
267  {
268  const size_t neededSize = 2 * items.size();
269  for (QuadTree& child : node->getChildren()) {
270  child.reserveItems(neededSize);
271  }
272 
273  for (Item* item : items) {
274  if (item->isUsed()) continue;
275 
276  for (QuadTree& child : node->getChildren()) {
277  if (isInNode(&child, item->getPointer())) {
278  child.insertItem(item);
279  }
280  }
281  }
282  afterFillDebugHook(node->getChildren());
283  }
284 
289  void callResultFunction(QuadTree* node, const CandidateReceiver& candidateReceiver) const
290  {
291  const std::vector<Item*>& foundItems = node->getItems();
292  std::vector<AData*> candidate;
293  candidate.reserve(foundItems.size());
294 
295  for (Item* item : foundItems) {
296  item->setUsedFlag();
297  candidate.push_back(item->getPointer());
298  }
299 
300  candidateReceiver(candidate, node);
301  }
302 
303  protected: // Section of specialisable functions
312  virtual XYSpans createChild(QuadTree* node, int iX, int iY) const
313  {
314  AX xMin = node->getXLowerBound(iX);
315  AX xMax = node->getXUpperBound(iX);
316  AY yMin = node->getYLowerBound(iY);
317  AY yMax = node->getYUpperBound(iY);
318  return XYSpans({xMin, xMax}, {yMin, yMax});
319  }
320 
328  virtual bool isInNode(QuadTree* node, AData* item) const = 0;
329 
335  virtual bool isLeaf(QuadTree* node) const
336  {
337  if (node->getLevel() >= m_lastLevel) {
338  return true;
339  } else {
340  return false;
341  }
342  }
343 
347  int getLastLevel() const
348  {
349  return m_lastLevel;
350  }
351 
352  public: // debug stuff
357  virtual void afterFillDebugHook(QuadTreeChildren& children)
358  {
359  if (not m_debugOutput) return;
360  for (QuadTree& childNode : children) {
361  if (childNode.getLevel() != getLastLevel()) continue; // Only write the lowest level
362  //m_debugOutputMap[ {childNode.getXMean(), childNode.getYMean()}] = childNode.getItems();
363  }
364  }
365 
369  const std::map<std::pair<AX, AY>, std::vector<Item*>>& getDebugInformation() const
370  {
371  return m_debugOutputMap;
372  }
373 
374  protected:
376  std::unique_ptr<QuadTree> m_quadTree;
377 
379  std::deque<Item> m_items;
380 
386  std::vector<QuadTree*> m_seededTrees;
387 
388  private:
390  int m_lastLevel;
391 
393  int m_seedLevel;
394 
396  bool m_debugOutput;
397 
399  std::map<std::pair<AX, AY>, std::vector<Item*>> m_debugOutputMap;
400  };
401  }
403 }
Belle2::TrackFindingCDC::QuadTreeProcessor::m_seedLevel
int m_seedLevel
The first level to be filled, effectivelly skip forward to this higher granularity level.
Definition: QuadTreeProcessor.h:401
Belle2::TrackFindingCDC::QuadTreeProcessor::m_debugOutputMap
std::map< std::pair< AX, AY >, std::vector< Item * > > m_debugOutputMap
The calculated debug map.
Definition: QuadTreeProcessor.h:407
Belle2::TrackFindingCDC::QuadTreeNode::YSpan
std::array< AY, 2 > YSpan
Type for a span in the Y direction that is covered by the tree.
Definition: QuadTreeNode.h:49
Belle2::TrackFindingCDC::QuadTreeProcessor::Item
QuadTreeItem< AData > Item
The QuadTree will only see items of this type.
Definition: QuadTreeProcessor.h:51
Belle2::TrackFindingCDC::QuadTreeProcessor::fill
void fill(const CandidateReceiver &candidateReceiver, int nHitsThreshold)
Start filling the already created tree.
Definition: QuadTreeProcessor.h:177
Belle2::TrackFindingCDC::QuadTreeProcessor::seed
void seed(std::vector< AData * > &datas)
Fill in the items in the given vector.
Definition: QuadTreeProcessor.h:112
Belle2::TrackFindingCDC::QuadTreeProcessor::XYSpans
std::pair< XSpan, YSpan > XYSpans
This pair of spans describes the span of a node.
Definition: QuadTreeProcessor.h:63
Belle2::TrackFindingCDC::QuadTreeProcessor::m_quadTree
std::unique_ptr< QuadTree > m_quadTree
The quad tree we work with.
Definition: QuadTreeProcessor.h:384
Belle2::TrackFindingCDC::QuadTreeProcessor::getDebugInformation
const std::map< std::pair< AX, AY >, std::vector< Item * > > & getDebugInformation() const
Return the debug information if collected.
Definition: QuadTreeProcessor.h:377
Belle2::TrackFindingCDC::QuadTreeProcessor::QuadTreeProcessor
QuadTreeProcessor(int lastLevel, int seedLevel, const XYSpans &xySpans, bool debugOutput=false)
Constructor is very simple.
Definition: QuadTreeProcessor.h:78
Belle2::TrackFindingCDC::QuadTreeProcessor::m_debugOutput
bool m_debugOutput
A flag to control the creation of the debug output.
Definition: QuadTreeProcessor.h:404
Belle2::TrackFindingCDC::QuadTreeProcessor::createChildren
void createChildren(QuadTree *node, QuadTreeChildren &m_children) const
Creates the sub node of a given node.
Definition: QuadTreeProcessor.h:258
Belle2::TrackFindingCDC::QuadTreeProcessor::isInNode
virtual bool isInNode(QuadTree *node, AData *item) const =0
Implement that function if you want to provide a new processor.
Belle2::TrackFindingCDC::QuadTreeProcessor::m_items
std::deque< Item > m_items
Storage space for the items that are referenced by the quad tree nodes.
Definition: QuadTreeProcessor.h:387
Belle2::TrackFindingCDC::QuadTreeProcessor::callResultFunction
void callResultFunction(QuadTree *node, const CandidateReceiver &candidateReceiver) const
When a node is accepted as a result, we extract a vector with the items (back transformed to AData*) ...
Definition: QuadTreeProcessor.h:297
Belle2::TrackFindingCDC::QuadTreeProcessor::fillChildren
void fillChildren(QuadTree *node, std::vector< Item * > &items)
This function is called by fillGivenTree and fills the items into the corresponding children.
Definition: QuadTreeProcessor.h:274
Belle2::TrackFindingCDC::QuadTreeNode::Children
std::vector< This > Children
Type of the child node structure for this node.
Definition: QuadTreeNode.h:58
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::TrackFindingCDC::QuadTreeNode::getChildren
Children & getChildren()
Returns the children structure of this node.
Definition: QuadTreeNode.h:118
Belle2::TrackFindingCDC::QuadTreeProcessor::QuadTree
QuadTreeNode< AX, AY, Item > QuadTree
The used QuadTree.
Definition: QuadTreeProcessor.h:54
Belle2::TrackFindingCDC::QuadTreeNode::XSpan
std::array< AX, 2 > XSpan
Type for a span in the X direction that is covered by the tree.
Definition: QuadTreeNode.h:46
Belle2::TrackFindingCDC::QuadTreeNode
Class which holds quadtree structure.
Definition: QuadTreeNode.h:39
Belle2::TrackFindingCDC::QuadTreeProcessor::fillGivenTree
void fillGivenTree(QuadTree *node, const CandidateReceiver &candidateReceiver, int nItemsThreshold, AY yLimit)
Internal function to do the real quad tree search: fill the nodes, check which of the n*m bins we nee...
Definition: QuadTreeProcessor.h:206
Belle2::TrackFindingCDC::QuadTreeProcessor::QuadTreeChildren
typename QuadTree::Children QuadTreeChildren
Alias for the QuadTree Children.
Definition: QuadTreeProcessor.h:66
Belle2::TrackFindingCDC::QuadTreeProcessor::afterFillDebugHook
virtual void afterFillDebugHook(QuadTreeChildren &children)
Override that function if you want to receive debug output whenever the children of a node are filled...
Definition: QuadTreeProcessor.h:365
Belle2::TrackFindingCDC::QuadTreeProcessor::getAssignedItems
std::vector< AData * > getAssignedItems()
Get items that have been assigned to the seed level The returned elements are unique even if items ar...
Definition: QuadTreeProcessor.h:158
Belle2::TrackFindingCDC::QuadTreeProcessor::~QuadTreeProcessor
virtual ~QuadTreeProcessor()
Destructor deletes the quad tree.
Definition: QuadTreeProcessor.h:93
Belle2::TrackFindingCDC::QuadTreeNode::getLevel
int getLevel() const
Returns level of the node in tree (i.e., how much ancestors the node has)
Definition: QuadTreeNode.h:135
Belle2::TrackFindingCDC::QuadTreeProcessor::CandidateReceiver
std::function< void(const std::vector< AData * > &, QuadTree *)> CandidateReceiver
This lambda function can be used for postprocessing.
Definition: QuadTreeProcessor.h:69
Belle2::TrackFindingCDC::QuadTreeProcessor::XSpan
typename QuadTree::XSpan XSpan
This pair describes the span in X for a node.
Definition: QuadTreeProcessor.h:57
Belle2::TrackFindingCDC::QuadTreeProcessor::clear
void clear()
Delete all the QuadTreeItems in the tree and clear the tree.
Definition: QuadTreeProcessor.h:101
Belle2::TrackFindingCDC::QuadTreeProcessor::createChild
virtual XYSpans createChild(QuadTree *node, int iX, int iY) const
Implement that function if you want to provide a new processor.
Definition: QuadTreeProcessor.h:320
Belle2::TrackFindingCDC::QuadTreeProcessor::m_lastLevel
int m_lastLevel
The last level to be filled.
Definition: QuadTreeProcessor.h:398
Belle2::TrackFindingCDC::QuadTreeProcessor::getLastLevel
int getLastLevel() const
Return the parameter last level.
Definition: QuadTreeProcessor.h:355
Belle2::TrackFindingCDC::QuadTreeProcessor::YSpan
typename QuadTree::YSpan YSpan
This pair describes the span in Y for a node.
Definition: QuadTreeProcessor.h:60
Belle2::TrackFindingCDC::QuadTreeItem
This class serves as a wrapper around all things that should go into a QuadTree.
Definition: QuadTreeItem.h:37
Belle2::TrackFindingCDC::QuadTreeProcessor::isLeaf
virtual bool isLeaf(QuadTree *node) const
Function which checks if given node is leaf Implemented as virtual to keep possibility of changing la...
Definition: QuadTreeProcessor.h:343
Belle2::TrackFindingCDC::QuadTreeProcessor::m_seededTrees
std::vector< QuadTree * > m_seededTrees
Vector of QuadTrees QuadTree instances (which are filled in the vector) cover the whole Legendre phas...
Definition: QuadTreeProcessor.h:394