Belle II Software prerelease-11-00-00e
AxialHitQuadTreeProcessor Class Referenceabstract

A QuadTreeProcessor for TrackHits. More...

#include <AxialHitQuadTreeProcessor.h>

Inheritance diagram for AxialHitQuadTreeProcessor:
Collaboration diagram for AxialHitQuadTreeProcessor:

Classes

struct  NodeCache
 Geometry of a node that is needed in the containment check. More...
 
struct  ThetaSpanCache
 Quantities entering the node containment check that only depend on the hit and on the theta span of a node - shared by all nodes that have the same theta span. More...
 

Public Types

using Item
 The QuadTree will only see items of this type.
 
using QuadTree
 The used QuadTree.
 
using XSpan
 This pair describes the span in X for a node.
 
using YSpan
 This pair describes the span in Y for a node.
 
using XYSpans
 This pair of spans describes the span of a node.
 
using QuadTreeChildren
 Alias for the QuadTree Children.
 
using CandidateReceiver
 This lambda function can be used for postprocessing.
 

Public Member Functions

 AxialHitQuadTreeProcessor (int lastLevel, int seedLevel, const XYSpans &ranges, PrecisionUtil::PrecisionFunction precisionFunction)
 Constructor.
 
 AxialHitQuadTreeProcessor (const TrackingUtilities::Vector2D &localOrigin, const YSpan &curvSpan, const TrackingUtilities::LookupTable< TrackingUtilities::Vector2D > *cosSinLookupTable)
 Constructor for the quad tree processor used in the off-origin extension.
 
void drawHits (std::vector< const TrackingUtilities::CDCWireHit * > hits, unsigned int color=46) const
 Draw QuadTree node.
 
void drawNode (QuadTree *node) const
 Draw QuadTree node.
 
void clear ()
 Delete all the QuadTreeItems in the tree and clear the tree.
 
void seed (const std::vector< const TrackingUtilities::CDCWireHit * > &datas)
 Fill in the items in the given vector.
 
std::vector< const TrackingUtilities::CDCWireHit * > getAssignedItems ()
 Get items that have been assigned to the seed level The returned elements are unique even if items are assigned multiple times.
 
void fill (const CandidateReceiver &candidateReceiver, int nHitsThreshold)
 Start filling the already created tree.
 
void fill (const CandidateReceiver &candidateReceiver, int nHitsThreshold, float yLimit)
 Fill vector of QuadTree instances with hits.
 
virtual void afterFillDebugHook (QuadTreeChildren &children)
 Override that function if you want to receive debug output whenever the children of a node are filled the first time Maybe you want to make some nice plots or statistics.
 
const std::map< std::pair< long, float >, std::vector< Item * > > & getDebugInformation () const
 Return the debug information if collected.
 

Static Public Member Functions

static const TrackingUtilities::LookupTable< TrackingUtilities::Vector2D > & getCosSinLookupTable ()
 Get the standard lookup table containing equally spaces unit vectors (cos, sin)
 
static std::vector< float > createCurvBound (YSpan curvSpan, int lastLevel)
 Constructs an array with the curvature bounds as generated by the default bin divisions.
 

Protected Member Functions

bool isLeaf (QuadTree *node) const final
 lastLevel depends on curvature of the track candidate
 
XYSpans createChild (QuadTree *node, int i, int j) const final
 Return the new ranges.
 
bool isInNode (QuadTree *node, const TrackingUtilities::CDCWireHit *wireHit) const final
 Check whether hit belongs to the quadtree node:
 
void insertItemsInNodes (const std::vector< QuadTree * > &nodes, const std::vector< Item * > &items) final
 Insert the hits into the given nodes sharing the parts of the containment check that do not depend on the individual node.
 
bool checkDerivative (QuadTree *node, const TrackingUtilities::CDCWireHit *wireHit) const
 Check derivative of the Legendre curve.
 
bool checkExtremum (QuadTree *node, const TrackingUtilities::CDCWireHit *wireHit) const
 Checks whether extreme point is located within QuadTree node's ranges.
 
virtual XYSpans createChild (QuadTree *node, int iX, int iY) const
 Implement that function if you want to provide a new processor.
 
virtual bool isInNode (QuadTree *node, const TrackingUtilities::CDCWireHit *item) const=0
 Implement that function if you want to provide a new processor.
 
virtual void insertItemsInNodes (const std::vector< QuadTree * > &nodes, const std::vector< Item * > &items)
 Insert each of the given items into every one of the given nodes it belongs to.
 
virtual bool isLeaf (QuadTree *node) const
 Function which checks if given node is leaf Implemented as virtual to keep possibility of changing lastLevel values depending on region is phase-space (i.e.
 
int getLastLevel () const
 Return the parameter last level.
 

Protected Attributes

std::unique_ptr< QuadTree > m_quadTree
 The quad tree we work with.
 
std::deque< Item > m_items
 Storage space for the items that are referenced by the quad tree nodes.
 
std::vector< Item * > m_itemPtrs
 Reusable buffer with pointers to all items - used to seed the tree.
 
std::vector< QuadTree * > m_childPtrs
 Reusable buffer with pointers to the children of the node currently being filled.
 
std::vector< QuadTree * > m_seededTrees
 Vector of QuadTrees QuadTree instances (which are filled in the vector) cover the whole Legendre phase-space; each instance is processes independently.
 

Private Member Functions

void fillGivenTree (QuadTree *node, const CandidateReceiver &candidateReceiver, int nItemsThreshold, float yLimit)
 Internal function to do the real quad tree search: fill the nodes, check which of the n*m bins we need to process further and go one level deeper.
 
void createChildren (QuadTree *node, QuadTreeChildren &m_children) const
 Creates the sub node of a given node.
 
void fillChildren (QuadTree *node, const std::vector< Item * > &items)
 This function is called by fillGivenTree and fills the items into the corresponding children.
 
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*) and pass it together with the result node to the candidate receiver function.
 

Private Attributes

std::vector< ThetaSpanCache > m_thetaSpanCaches
 Reusable buffer with the per theta span quantities - one entry per distinct theta span.
 
std::vector< NodeCache > m_nodeCaches
 Reusable buffer with the per node quantities - one entry per node.
 
PrecisionUtil::PrecisionFunction m_precisionFunction
 Lambda which holds resolution function for the quadtree.
 
TrackingUtilities::Vector2D m_localOrigin
 Local origin on which the phase space coordinates are centered.
 
const TrackingUtilities::LookupTable< TrackingUtilities::Vector2D > * m_cosSinLookupTable
 Pinned lookup table for precomputed cosine and sine values.
 
const double c_curlCurv = 0.02
 The curvature above which the trajectory is considered a curler.
 
bool m_twoSidedPhaseSpace
 Indicator whether the two sided phases space insertion check should be used This option should automatically split back to back tracks in the low curvature regions.
 
int m_lastLevel
 The last level to be filled.
 
int m_seedLevel
 The first level to be filled, effectively skip forward to this higher granularity level.
 
bool m_debugOutput
 A flag to control the creation of the debug output.
 
std::map< std::pair< long, float >, std::vector< Item * > > m_debugOutputMap
 The calculated debug map.
 

Static Private Attributes

static const int c_maxNChildren
 Upper bound on the number of children of a node - they are kept on the stack.
 

Detailed Description

A QuadTreeProcessor for TrackHits.

Definition at line 31 of file AxialHitQuadTreeProcessor.h.

Member Typedef Documentation

◆ CandidateReceiver

using CandidateReceiver
inherited

This lambda function can be used for postprocessing.

Definition at line 69 of file QuadTreeProcessor.h.

◆ Item

using Item
inherited

The QuadTree will only see items of this type.

Definition at line 51 of file QuadTreeProcessor.h.

◆ QuadTree

using QuadTree
inherited

The used QuadTree.

Definition at line 54 of file QuadTreeProcessor.h.

◆ QuadTreeChildren

using QuadTreeChildren
inherited

Alias for the QuadTree Children.

Definition at line 66 of file QuadTreeProcessor.h.

◆ XSpan

using XSpan
inherited

This pair describes the span in X for a node.

Definition at line 57 of file QuadTreeProcessor.h.

◆ XYSpans

using XYSpans
inherited

This pair of spans describes the span of a node.

Definition at line 63 of file QuadTreeProcessor.h.

◆ YSpan

using YSpan
inherited

This pair describes the span in Y for a node.

Definition at line 60 of file QuadTreeProcessor.h.

Constructor & Destructor Documentation

◆ AxialHitQuadTreeProcessor() [1/2]

AxialHitQuadTreeProcessor ( int lastLevel,
int seedLevel,
const XYSpans & ranges,
PrecisionUtil::PrecisionFunction precisionFunction )

Constructor.

Definition at line 97 of file AxialHitQuadTreeProcessor.cc.

101 : QuadTreeProcessor(lastLevel, seedLevel, ranges)
102 , m_precisionFunction(precisionFunction)
103 , m_localOrigin(0.0, 0.0)
105{
106 m_twoSidedPhaseSpace = m_quadTree->getYMin() * m_quadTree->getYMax() < 0;
107}
bool m_twoSidedPhaseSpace
Indicator whether the two sided phases space insertion check should be used This option should automa...
TrackingUtilities::Vector2D m_localOrigin
Local origin on which the phase space coordinates are centered.
PrecisionUtil::PrecisionFunction m_precisionFunction
Lambda which holds resolution function for the quadtree.
static const TrackingUtilities::LookupTable< TrackingUtilities::Vector2D > & getCosSinLookupTable()
Get the standard lookup table containing equally spaces unit vectors (cos, sin)
const TrackingUtilities::LookupTable< TrackingUtilities::Vector2D > * m_cosSinLookupTable
Pinned lookup table for precomputed cosine and sine values.
QuadTreeProcessor(int lastLevel, int seedLevel, const XYSpans &xySpans, bool debugOutput=false)

◆ AxialHitQuadTreeProcessor() [2/2]

AxialHitQuadTreeProcessor ( const TrackingUtilities::Vector2D & localOrigin,
const YSpan & curvSpan,
const TrackingUtilities::LookupTable< TrackingUtilities::Vector2D > * cosSinLookupTable )

Constructor for the quad tree processor used in the off-origin extension.

Currently only used in zero level mode to collect hits that are in a phase space part with respect to the given point.

Definition at line 109 of file AxialHitQuadTreeProcessor.cc.

112 : QuadTreeProcessor(0, 0, { {0, cosSinLookupTable->getNPoints() - 1}, curvSpan})
113, m_localOrigin(localOrigin)
114, m_cosSinLookupTable(cosSinLookupTable)
115{
116 // Never use two sided mode in off origin extension
117 m_twoSidedPhaseSpace = false;
118}

Member Function Documentation

◆ afterFillDebugHook()

virtual void afterFillDebugHook ( QuadTreeChildren & children)
inlinevirtualinherited

Override that function if you want to receive debug output whenever the children of a node are filled the first time Maybe you want to make some nice plots or statistics.

Definition at line 392 of file QuadTreeProcessor.h.

393 {
394 if (not m_debugOutput) return;
395 for (QuadTree& childNode : children) {
396 if (childNode.getLevel() != getLastLevel()) continue; // Only write the lowest level
397 //m_debugOutputMap[ {childNode.getXMean(), childNode.getYMean()}] = childNode.getItems();
398 }
399 }

◆ callResultFunction()

void callResultFunction ( QuadTree * node,
const CandidateReceiver & candidateReceiver ) const
inlineprivateinherited

When a node is accepted as a result, we extract a vector with the items (back transformed to AData*) and pass it together with the result node to the candidate receiver function.

Definition at line 301 of file QuadTreeProcessor.h.

302 {
303 const std::vector<Item*>& foundItems = node->getItems();
304 std::vector<AData*> candidate;
305 candidate.reserve(foundItems.size());
306
307 for (Item* item : foundItems) {
308 item->setUsedFlag();
309 candidate.push_back(item->getPointer());
310 }
311
312 candidateReceiver(candidate, node);
313 }

◆ checkDerivative()

bool checkDerivative ( QuadTree * node,
const TrackingUtilities::CDCWireHit * wireHit ) const
protected

Check derivative of the Legendre curve.

Parameters
nodeQuadTree node
wireHitpointer to the hit to check
Returns
returns true in cases:
- positive derivative and no extremum in the node's ranges or
- extremum located in the node's ranges
returns false in other cases (namely negative derivative

Definition at line 396 of file AxialHitQuadTreeProcessor.cc.

397{
398 const Vector2D& pos2D = wireHit->getRefPos2D() - m_localOrigin;
399
400 long thetaMin = node->getXMin();
401 long thetaMax = node->getXMax();
402
403 const Vector2D& thetaVecMin = m_cosSinLookupTable->at(thetaMin);
404 const Vector2D& thetaVecMax = m_cosSinLookupTable->at(thetaMax);
405
406 float rMinD = thetaVecMin.cross(pos2D);
407 float rMaxD = thetaVecMax.cross(pos2D);
408
409 // Does not really make sense...
410 if ((rMinD > 0) && (rMaxD * rMinD >= 0)) return true;
411 if ((rMaxD * rMinD < 0)) return true;
412 return false;
413}
double cross(const Vector2D &rhs) const
Calculated the two dimensional cross product.
Definition Vector2D.h:185

◆ checkExtremum()

bool checkExtremum ( QuadTree * node,
const TrackingUtilities::CDCWireHit * wireHit ) const
protected

Checks whether extreme point is located within QuadTree node's ranges.

Parameters
nodeQuadTree node
wireHithit to check
Returns
true or false

Definition at line 415 of file AxialHitQuadTreeProcessor.cc.

416{
417 const double& driftLength = wireHit->getRefDriftLength();
418 const Vector2D& pos2D = wireHit->getRefPos2D() - m_localOrigin;
419 double r2 = pos2D.normSquared() - driftLength * driftLength;
420
421 // get left and right borders of the node
422 long thetaMin = node->getXMin();
423 long thetaMax = node->getXMax();
424
425 const Vector2D& thetaVecMin = m_cosSinLookupTable->at(thetaMin);
426 const Vector2D& thetaVecMax = m_cosSinLookupTable->at(thetaMax);
427
428 if (not pos2D.isBetween(thetaVecMin, thetaVecMax)) return false;
429
430 // compute Legendre curves at the position
431 double r = pos2D.norm();
432 float rRight = r - driftLength;
433 float rLeft = r + driftLength;
434
435 // get top and bottom borders of the node
436 float rMin = node->getYMin() * r2 / 2;
437 float rMax = node->getYMax() * r2 / 2;
438
439 bool crossesRight = (rMin - rRight) * (rMax - rRight) < 0;
440 bool crossesLeft = (rMin - rLeft) * (rMax - rLeft) < 0;
441 return crossesRight or crossesLeft;
442}
bool isBetween(const Vector2D &lower, const Vector2D &upper) const
Checks if this vector is between two other vectors Between means here that when rotating the lower ve...
Definition Vector2D.h:552
double normSquared() const
Calculates .
Definition Vector2D.h:191
double norm() const
Calculates the length of the vector.
Definition Vector2D.h:202

◆ clear()

void clear ( )
inlineinherited

Delete all the QuadTreeItems in the tree and clear the tree.

Definition at line 102 of file QuadTreeProcessor.h.

103 {
104 m_seededTrees.clear();
105 m_quadTree->clearChildren();
106 m_quadTree->clearItems();
107 m_items.clear();
108 }

◆ createChild() [1/2]

AxialHitQuadTreeProcessor::XYSpans createChild ( QuadTree * node,
int i,
int j ) const
finalprotected

Return the new ranges.

We do not use the standard ranges for the lower levels.

Parameters
nodequadtree node
itheta index of the child
jrho index of the child
Returns
returns ranges of the (i;j) child

Definition at line 136 of file AxialHitQuadTreeProcessor.cc.

137{
138 const int nodeLevel = node->getLevel();
139 const int lastLevel = getLastLevel();
140 const float meanCurv = std::fabs(node->getYMax() + node->getYMin()) / 2;
141
142 // Expand bins for all nodes 7 levels before the last level (for lastLevel = 12 starting at 6)
143 // but only in a curvature region higher than 0.005. Lower than that use always standard.
144 bool standardBinning = (nodeLevel <= lastLevel - 7) or (meanCurv <= 0.005);
145
146 if (standardBinning) {
147 float r1 = node->getYLowerBound(j);
148 float r2 = node->getYUpperBound(j);
149 long theta1 = node->getXLowerBound(i);
150 long theta2 = node->getXUpperBound(i);
151
152 // Standard bin division
153 return XYSpans({theta1, theta2}, {r1, r2});
154 }
155
156 // Non-standard binning
157 // For level 6 to 7 only expand 1 / 4, for higher levels expand 1 / 8.
158 // (assuming last level == 12)
159 if (nodeLevel < lastLevel - 5) {
160 float r1 = node->getYLowerBound(j) - node->getYBinWidth(j) / 4.;
161 float r2 = node->getYUpperBound(j) + node->getYBinWidth(j) / 4.;
162
163 // long extension = pow(2, lastLevel - nodeLevel) / 4; is same as:
164 long extension = pow(2, lastLevel - nodeLevel - 2);
165
166 long theta1 = node->getXLowerBound(i) - extension;
167 if (theta1 < 0) theta1 = 0;
168
169 long theta2 = node->getXUpperBound(i) + extension;
170 if (theta2 >= m_cosSinLookupTable->getNPoints()) {
171 theta2 = m_cosSinLookupTable->getNPoints() - 1;
172 }
173
174 return XYSpans({theta1, theta2}, {r1, r2});
175 } else {
176 float r1 = node->getYLowerBound(j) - node->getYBinWidth(j) / 8.;
177 float r2 = node->getYUpperBound(j) + node->getYBinWidth(j) / 8.;
178
179 // long extension = pow(2, lastLevel - nodeLevel) / 8; is same as
180 long extension = pow(2, lastLevel - nodeLevel - 3);
181
182 long theta1 = node->getXLowerBound(i) - extension;
183 if (theta1 < 0) theta1 = 0;
184
185 long theta2 = node->getXUpperBound(i) + extension;
186 if (theta2 >= m_cosSinLookupTable->getNPoints()) {
187 theta2 = m_cosSinLookupTable->getNPoints() - 1;
188 }
189
190 return XYSpans({theta1, theta2}, {r1, r2});
191 }
192}

◆ createChild() [2/2]

virtual XYSpans createChild ( QuadTree * node,
int iX,
int iY ) const
inlineprotectedvirtualinherited

Implement that function if you want to provide a new processor.

It decides which node-spans the n * m children of the node should have. It is called when creating the nodes. The two indices iX and iY tell you where the new node will be created (as node.children[iX][iY]). You can check some information on the level or the x- or y-values by using the methods implemented for node.

Returns
a XYSpan pair of a x- and a y-span that the new child should have. If you don nt want to provide custom spans, just return XYSpans(XSpan(node->getXBinBound(iX), node->getXBinBound(iX + 1)), YSpan(node->getYBinBound(iY), node->getYBinBound(iY + 1)));

Definition at line 324 of file QuadTreeProcessor.h.

325 {
326 AX xMin = node->getXLowerBound(iX);
327 AX xMax = node->getXUpperBound(iX);
328 AY yMin = node->getYLowerBound(iY);
329 AY yMax = node->getYUpperBound(iY);
330 return XYSpans({xMin, xMax}, {yMin, yMax});
331 }

◆ createChildren()

void createChildren ( QuadTree * node,
QuadTreeChildren & m_children ) const
inlineprivateinherited

Creates the sub node of a given node.

This function is called by fillGivenTree. To calculate the spans of the children nodes the user-defined function createChiildWithParent is used.

Definition at line 264 of file QuadTreeProcessor.h.

265 {
266 m_children.reserve(node->getXNbins() * node->getYNbins());
267 for (int i = 0; i < node->getXNbins(); ++i) {
268 for (int j = 0; j < node->getYNbins(); ++j) {
269 const XYSpans& xySpans = createChild(node, i, j);
270 const XSpan& xSpan = xySpans.first;
271 const YSpan& ySpan = xySpans.second;
272 m_children.push_back(QuadTree(xSpan, ySpan, node->getLevel() + 1, node));
273 }
274 }
275 }

◆ createCurvBound()

std::vector< float > createCurvBound ( YSpan curvSpan,
int lastLevel )
static

Constructs an array with the curvature bounds as generated by the default bin divisions.

Definition at line 65 of file AxialHitQuadTreeProcessor.cc.

66{
67 std::vector<YSpan> spans{{curvSpan}};
68
69 std::vector<YSpan> nextSpans;
70 for (int level = 1; level <= lastLevel; ++level) {
71 nextSpans.clear();
72 for (const YSpan& span : spans) {
73 nextSpans.push_back(splitCurvSpan(span, level, lastLevel, 0));
74 nextSpans.push_back(splitCurvSpan(span, level, lastLevel, 1));
75 }
76 spans.swap(nextSpans);
77 }
78
79 std::vector<float> bounds;
80 for (const YSpan& span : spans) {
81 bounds.push_back(span[0]);
82 bounds.push_back(span[1]);
83 }
84
85 assert(bounds.size() == std::pow(2, lastLevel));
86 return bounds;
87}

◆ drawHits()

void drawHits ( std::vector< const TrackingUtilities::CDCWireHit * > hits,
unsigned int color = 46 ) const

Draw QuadTree node.

Definition at line 444 of file AxialHitQuadTreeProcessor.cc.

445{
446 static int nevent(0);
447
448 TCanvas* canv = new TCanvas("canv", "legendre transform", 0, 0, 1200, 600);
449 canv->cd(1);
450 TGraph* dummyGraph = new TGraph();
451 dummyGraph->SetPoint(1, -M_PI, 0);
452 dummyGraph->SetPoint(2, M_PI, 0);
453 dummyGraph->Draw("AP");
454 dummyGraph->GetXaxis()->SetTitle("#theta");
455 dummyGraph->GetYaxis()->SetTitle("#rho");
456 dummyGraph->GetXaxis()->SetRangeUser(-M_PI, M_PI);
457 dummyGraph->GetYaxis()->SetRangeUser(-0.02, 0.15);
458
459 for (const CDCWireHit* wireHit : hits) {
460 const double& driftLength = wireHit->getRefDriftLength();
461 const Vector2D& pos2D = wireHit->getRefPos2D() - m_localOrigin;
462 double x = pos2D.x();
463 double y = pos2D.y();
464 double r2 = pos2D.normSquared() - driftLength * driftLength;
465
466 TF1* concaveHitLegendre = new TF1("concaveHitLegendre", "2*([0]/[3])*cos(x) + 2*([1]/[3])*sin(x) + 2*([2]/[3])", -M_PI, M_PI);
467 TF1* convexHitLegendre = new TF1("convexHitLegendre", "2*([0]/[3])*cos(x) + 2*([1]/[3])*sin(x) - 2*([2]/[3])", -M_PI, M_PI);
468 concaveHitLegendre->SetLineWidth(1);
469 convexHitLegendre->SetLineWidth(1);
470 concaveHitLegendre->SetLineColor(color);
471 convexHitLegendre->SetLineColor(color);
472
473 concaveHitLegendre->SetParameters(x, y, driftLength, r2);
474 convexHitLegendre->SetParameters(x, y, driftLength, r2);
475 concaveHitLegendre->Draw("CSAME");
476 convexHitLegendre->Draw("CSAME");
477 }
478// canv->Print(Form("legendreHits_%i.root", nevent));
479// canv->Print(Form("legendreHits_%i.eps", nevent));
480 canv->Print(Form("legendreHits_%i.png", nevent));
481 delete canv;
482
483 nevent++;
484}
double x() const
Getter for the x coordinate.
Definition Vector2D.h:622
double y() const
Getter for the y coordinate.
Definition Vector2D.h:637

◆ drawNode()

void drawNode ( QuadTree * node) const

Draw QuadTree node.

Definition at line 486 of file AxialHitQuadTreeProcessor.cc.

487{
488 std::vector<const CDCWireHit*> hits;
489 for (Item* item : node->getItems()) {
490 const CDCWireHit* wireHit = item->getPointer();
491 hits.push_back(wireHit);
492 }
493 drawHits(hits);
494}
void drawHits(std::vector< const TrackingUtilities::CDCWireHit * > hits, unsigned int color=46) const
Draw QuadTree node.

◆ fill() [1/2]

void fill ( const CandidateReceiver & candidateReceiver,
int nHitsThreshold )
inlineinherited

Start filling the already created tree.

Parameters
candidateReceiverthe lambda function to call after a node was selected
nHitsThresholdthe threshold on the number of items

Definition at line 179 of file QuadTreeProcessor.h.

180 {
181 fill(candidateReceiver, nHitsThreshold, std::numeric_limits<AY>::max());
182 }

◆ fill() [2/2]

void fill ( const CandidateReceiver & candidateReceiver,
int nHitsThreshold,
float yLimit )
inlineinherited

Fill vector of QuadTree instances with hits.

Parameters
candidateReceiverthe lambda function to call after a node was selected
nHitsThresholdthe threshold on the number of items
yLimitthe threshold in the rho (curvature) variable

Definition at line 190 of file QuadTreeProcessor.h.

191 {
192 std::vector<QuadTree*> quadTrees = m_seededTrees;
193 std::sort(quadTrees.begin(), quadTrees.end(), [](QuadTree * quadTree1, QuadTree * quadTree2) {
194 return quadTree1->getNItems() > quadTree2->getNItems();
195 });
196
197 for (QuadTree* tree : quadTrees) {
198 erase_remove_if(tree->getItems(), [](Item * hit) { return hit->isUsed(); });
199 fillGivenTree(tree, candidateReceiver, nHitsThreshold, yLimit);
200 }
201 }

◆ fillChildren()

void fillChildren ( QuadTree * node,
const std::vector< Item * > & items )
inlineprivateinherited

This function is called by fillGivenTree and fills the items into the corresponding children.

For this the user-defined method isInNode is called.

Definition at line 281 of file QuadTreeProcessor.h.

282 {
283 // An item can be inserted into each child at most once
284 const size_t neededSize = items.size();
285 m_childPtrs.clear();
286 m_childPtrs.reserve(node->getChildren().size());
287 for (QuadTree& child : node->getChildren()) {
288 child.reserveItems(neededSize);
289 m_childPtrs.push_back(&child);
290 }
291
292 this->insertItemsInNodes(m_childPtrs, items);
293
294 afterFillDebugHook(node->getChildren());
295 }

◆ fillGivenTree()

void fillGivenTree ( QuadTree * node,
const CandidateReceiver & candidateReceiver,
int nItemsThreshold,
float yLimit )
inlineprivateinherited

Internal function to do the real quad tree search: fill the nodes, check which of the n*m bins we need to process further and go one level deeper.

Definition at line 208 of file QuadTreeProcessor.h.

212 {
213 if (node->getNItems() < nItemsThreshold) {
214 return;
215 }
216
217 if ((node->getYMin() > yLimit) or (-node->getYMax() > yLimit)) {
218 return;
219 }
220
221 if (isLeaf(node)) {
222 callResultFunction(node, candidateReceiver);
223 return;
224 }
225
226 if (node->getChildren().empty()) {
227 this->createChildren(node, node->getChildren());
228 }
229
230 if (!node->checkFilled()) {
231 fillChildren(node, node->getItems());
232 node->setFilled();
233 }
234
235 // Kept on the stack - this function is called millions of times per event
236 std::array<QuadTree*, c_maxNChildren> children;
237 int nChildren = 0;
238 for (QuadTree& child : node->getChildren()) {
239 B2ASSERT("More children than the quad tree processor supports", nChildren < c_maxNChildren);
240 children[nChildren++] = &child;
241 }
242 const auto compareNItems = [](const QuadTree * lhs, const QuadTree * rhs) {
243 return lhs->getNItems() < rhs->getNItems();
244 };
245
246 // Explicitly count down the children
247 for (int nRemaining = nChildren; nRemaining > 0; --nRemaining) {
248 auto itHeaviestChild =
249 std::max_element(children.begin(), children.begin() + nRemaining, compareNItems);
250 QuadTree* heaviestChild = *itHeaviestChild;
251 // Drop the heaviest child from the list keeping the order of the remaining ones
252 std::move(itHeaviestChild + 1, children.begin() + nRemaining, itHeaviestChild);
253 // After we have processed some children we need to get rid of the already used hits in all the children,
254 // because this can change the number of items drastically
255 erase_remove_if(heaviestChild->getItems(), [&](Item * hit) { return hit->isUsed(); });
256 this->fillGivenTree(heaviestChild, candidateReceiver, nItemsThreshold, yLimit);
257 }
258 }

◆ getAssignedItems()

std::vector< const TrackingUtilities::CDCWireHit * > getAssignedItems ( )
inlineinherited

Get items that have been assigned to the seed level The returned elements are unique even if items are assigned multiple times.

Definition at line 160 of file QuadTreeProcessor.h.

161 {
162 std::vector<const TrackingUtilities::CDCWireHit*> result;
163 for (QuadTree* seededTree : m_seededTrees) {
164 for (Item* item : seededTree->getItems()) {
165 result.push_back(item->getPointer());
166 }
167 }
168 std::sort(result.begin(), result.end());
169 result.erase(std::unique(result.begin(), result.end()), result.end());
170 return result;
171 }

◆ getCosSinLookupTable()

const LookupTable< Vector2D > & getCosSinLookupTable ( )
static

Get the standard lookup table containing equally spaces unit vectors (cos, sin)

It contains 2**16 + 1 sampling points between -pi and pi.

Definition at line 89 of file AxialHitQuadTreeProcessor.cc.

90{
91 static const int maxLevel = PrecisionUtil::getLookupGridLevel();
92 static const int nBins = std::pow(2, maxLevel);
93 static LookupTable<Vector2D> trigonometricLookUpTable(&Vector2D::Phi, nBins, -M_PI, M_PI);
94 return trigonometricLookUpTable;
95}
static constexpr int getLookupGridLevel()
Returns desired deepness of the trigonometrical lookup table. Used as template parameter for the Trig...
static Vector2D Phi(const double phi)
Constructs a unit vector with azimuth angle equal to phi.
Definition Vector2D.h:78

◆ getDebugInformation()

const std::map< std::pair< long, float >, std::vector< Item * > > & getDebugInformation ( ) const
inlineinherited

Return the debug information if collected.

Definition at line 404 of file QuadTreeProcessor.h.

405 {
406 return m_debugOutputMap;
407 }

◆ getLastLevel()

int getLastLevel ( ) const
inlineprotectedinherited

Return the parameter last level.

Definition at line 382 of file QuadTreeProcessor.h.

383 {
384 return m_lastLevel;
385 }

◆ insertItemsInNodes() [1/2]

void insertItemsInNodes ( const std::vector< QuadTree * > & nodes,
const std::vector< Item * > & items )
finalprotected

Insert the hits into the given nodes sharing the parts of the containment check that do not depend on the individual node.

The nodes handed to this function - the children of a common parent or the nodes of the seed level - always form a grid in the phase space, in the sense that their theta spans only take a few distinct values. All quantities that only depend on the hit and on the theta span of a node are therefore computed once per hit and distinct theta span instead of once for every hit and node pair.

Definition at line 262 of file AxialHitQuadTreeProcessor.cc.

264{
265 const size_t nNodes = nodes.size();
266 if (nNodes == 0 or items.empty()) return;
267
268 // Collect the geometry of the nodes and group them by their theta span.
269 // The nodes handed here are either the four children of one node or the nodes of the seed
270 // level, which both cover only a handful of distinct theta spans.
271 m_thetaSpanCaches.clear();
272 m_nodeCaches.resize(nNodes);
273
274 for (size_t iNode = 0; iNode < nNodes; ++iNode) {
275 QuadTree* node = nodes[iNode];
276 NodeCache& nodeCache = m_nodeCaches[iNode];
277 nodeCache.yMin = node->getYMin();
278 nodeCache.yMax = node->getYMax();
279 nodeCache.needsDerivativeCheck = node->getLevel() <= 4 and m_twoSidedPhaseSpace and
280 nodeCache.yMin > -c_curlCurv and nodeCache.yMax < c_curlCurv;
281
282 const long xMin = node->getXMin();
283 const long xMax = node->getXMax();
284
285 size_t iThetaSpan = 0;
286 for (; iThetaSpan < m_thetaSpanCaches.size(); ++iThetaSpan) {
287 if (m_thetaSpanCaches[iThetaSpan].xMin == xMin and m_thetaSpanCaches[iThetaSpan].xMax == xMax) break;
288 }
289 if (iThetaSpan == m_thetaSpanCaches.size()) {
290 ThetaSpanCache thetaSpanCache;
291 thetaSpanCache.xMin = xMin;
292 thetaSpanCache.xMax = xMax;
293 thetaSpanCache.thetaVecMin = &m_cosSinLookupTable->at(xMin);
294 thetaSpanCache.thetaVecMax = &m_cosSinLookupTable->at(xMax);
295 m_thetaSpanCaches.push_back(thetaSpanCache);
296 }
297 nodeCache.iThetaSpan = iThetaSpan;
298 }
299
300 const size_t nThetaSpans = m_thetaSpanCaches.size();
301
302 for (Item* item : items) {
303 if (item->isUsed()) continue;
304
305 const CDCWireHit* wireHit = item->getPointer();
306
307 // Quantities that only depend on the hit
308 const double driftLength = wireHit->getRefDriftLength();
309 const Vector2D pos2D = wireHit->getRefPos2D() - m_localOrigin;
310 const double r2 = pos2D.normSquared() - driftLength * driftLength;
311
312 // Quantities that only depend on the hit and the theta span of a node
313 for (size_t iThetaSpan = 0; iThetaSpan < nThetaSpans; ++iThetaSpan) {
314 ThetaSpanCache& thetaSpanCache = m_thetaSpanCaches[iThetaSpan];
315 const Vector2D& thetaVecMin = *thetaSpanCache.thetaVecMin;
316 const Vector2D& thetaVecMax = *thetaSpanCache.thetaVecMax;
317
318 const float rHitMin = thetaVecMin.dot(pos2D);
319 const float rHitMax = thetaVecMax.dot(pos2D);
320
321 thetaSpanCache.rHitMinRight = rHitMin - driftLength;
322 thetaSpanCache.rHitMaxRight = rHitMax - driftLength;
323 thetaSpanCache.rHitMinLeft = rHitMin + driftLength;
324 thetaSpanCache.rHitMaxLeft = rHitMax + driftLength;
325
326 const float rHitMinExtr = thetaVecMin.cross(pos2D);
327 const float rHitMaxExtr = thetaVecMax.cross(pos2D);
328 thetaSpanCache.rHitMinExtr = rHitMinExtr;
329 thetaSpanCache.rHitMaxExtr = rHitMaxExtr;
330
331 // Same decision as checkDerivative()
332 thetaSpanCache.derivativeOk = ((rHitMinExtr > 0) and (rHitMaxExtr * rHitMinExtr >= 0)) or
333 (rHitMaxExtr * rHitMinExtr < 0);
334
335 thetaSpanCache.hasExtremum = rHitMinExtr * rHitMaxExtr < 0.;
336 if (thetaSpanCache.hasExtremum) {
337 thetaSpanCache.extremumIsBetween = pos2D.isBetween(thetaVecMin, thetaVecMax);
338 }
339 }
340
341 // Legendre curves at the extremum - only needed if some theta span contains the extremum
342 bool extremumComputed = false;
343 float rRight = 0;
344 float rLeft = 0;
345
346 for (size_t iNode = 0; iNode < nNodes; ++iNode) {
347 const NodeCache& nodeCache = m_nodeCaches[iNode];
348 const ThetaSpanCache& thetaSpanCache = m_thetaSpanCaches[nodeCache.iThetaSpan];
349
350 // Check whether the hit lies in the forward direction
351 if (nodeCache.needsDerivativeCheck and not thetaSpanCache.derivativeOk) continue;
352
353 // get top and bottom borders of the node
354 const float rMin = nodeCache.yMin * r2 / 2;
355 const float rMax = nodeCache.yMax * r2 / 2;
356
357 // Compare distance signs from the Legendre curves to the node
358 // Check right
359 if (not sameSign(rMin - thetaSpanCache.rHitMinRight,
360 rMin - thetaSpanCache.rHitMaxRight,
361 rMax - thetaSpanCache.rHitMinRight,
362 rMax - thetaSpanCache.rHitMaxRight)) {
363 nodes[iNode]->insertItem(item);
364 continue;
365 }
366
367 // Check left
368 if (not sameSign(rMin - thetaSpanCache.rHitMinLeft,
369 rMin - thetaSpanCache.rHitMaxLeft,
370 rMax - thetaSpanCache.rHitMinLeft,
371 rMax - thetaSpanCache.rHitMaxLeft)) {
372 nodes[iNode]->insertItem(item);
373 continue;
374 }
375
376 // Check the extremum
377 if (not thetaSpanCache.hasExtremum) continue;
378 if (not thetaSpanCache.extremumIsBetween) continue;
379
380 if (not extremumComputed) {
381 const double r = pos2D.norm();
382 rRight = r - driftLength;
383 rLeft = r + driftLength;
384 extremumComputed = true;
385 }
386
387 const bool crossesRight = (rMin - rRight) * (rMax - rRight) < 0;
388 const bool crossesLeft = (rMin - rLeft) * (rMax - rLeft) < 0;
389 if (crossesRight or crossesLeft) {
390 nodes[iNode]->insertItem(item);
391 }
392 }
393 }
394}
std::vector< ThetaSpanCache > m_thetaSpanCaches
Reusable buffer with the per theta span quantities - one entry per distinct theta span.
const double c_curlCurv
The curvature above which the trajectory is considered a curler.
std::vector< NodeCache > m_nodeCaches
Reusable buffer with the per node quantities - one entry per node.
double dot(const Vector2D &rhs) const
Calculates the two dimensional dot product.
Definition Vector2D.h:174
bool sameSign(double expected, double actual)
Predicate checking that two values have the same sign.
Geometry of a node that is needed in the containment check.
Quantities entering the node containment check that only depend on the hit and on the theta span of a...
long xMin
Lower theta bound of the nodes in this group as an index into the lookup table.

◆ insertItemsInNodes() [2/2]

virtual void insertItemsInNodes ( const std::vector< QuadTree * > & nodes,
const std::vector< Item * > & items )
inlineprotectedvirtualinherited

Insert each of the given items into every one of the given nodes it belongs to.

The default implementation simply asks isInNode for each item and node pair. Processors may override it to share the parts of the containment check that only depend on the item or on a part of the node geometry over the given set of nodes. Any implementation has to insert the items into each node in the order in which they appear in the given item range.

Definition at line 351 of file QuadTreeProcessor.h.

353 {
354 for (Item* item : items) {
355 if (item->isUsed()) continue;
356
357 for (QuadTree* node : nodes) {
358 if (isInNode(node, item->getPointer())) {
359 node->insertItem(item);
360 }
361 }
362 }
363 }

◆ isInNode() [1/2]

bool isInNode ( QuadTree * node,
const TrackingUtilities::CDCWireHit * wireHit ) const
finalprotected

Check whether hit belongs to the quadtree node:

Parameters
nodequadtree node
wireHithit being checked
Returns
returns true if Legendre curve of the hit crosses (geometrically) borders of the node

Definition at line 194 of file AxialHitQuadTreeProcessor.cc.

195{
196 // Check whether the hit lies in the forward direction
197 if (node->getLevel() <= 4 and m_twoSidedPhaseSpace and node->getYMin() > -c_curlCurv and
198 node->getYMax() < c_curlCurv) {
199 if (not checkDerivative(node, wireHit)) return false;
200 }
201
202 const double& driftLength = wireHit->getRefDriftLength();
203 const Vector2D& pos2D = wireHit->getRefPos2D() - m_localOrigin;
204 double r2 = pos2D.normSquared() - driftLength * driftLength;
205
206 using Quadlet = std::array<std::array<float, 2>, 2>;
207 Quadlet distRight{};
208 Quadlet distLeft{};
209
210 // get top and bottom borders of the node
211 float rMin = node->getYMin() * r2 / 2;
212 float rMax = node->getYMax() * r2 / 2;
213
214 // get left and right borders of the node
215 long thetaMin = node->getXMin();
216 long thetaMax = node->getXMax();
217
218 const Vector2D& thetaVecMin = m_cosSinLookupTable->at(thetaMin);
219 const Vector2D& thetaVecMax = m_cosSinLookupTable->at(thetaMax);
220
221 float rHitMin = thetaVecMin.dot(pos2D);
222 float rHitMax = thetaVecMax.dot(pos2D);
223
224 // compute Legendre curves at the left and right borders of the node
225 float rHitMinRight = rHitMin - driftLength;
226 float rHitMaxRight = rHitMax - driftLength;
227
228 float rHitMinLeft = rHitMin + driftLength;
229 float rHitMaxLeft = rHitMax + driftLength;
230
231 // Compute distance from the Legendre curves to bottom and top borders of the node
232 distRight[0][0] = rMin - rHitMinRight;
233 distRight[0][1] = rMin - rHitMaxRight;
234 distRight[1][0] = rMax - rHitMinRight;
235 distRight[1][1] = rMax - rHitMaxRight;
236
237 distLeft[0][0] = rMin - rHitMinLeft;
238 distLeft[0][1] = rMin - rHitMaxLeft;
239 distLeft[1][0] = rMax - rHitMinLeft;
240 distLeft[1][1] = rMax - rHitMaxLeft;
241
242 // Compare distance signs from Legendre curves to the node
243 // Check right
244 if (not sameSign(distRight[0][0], distRight[0][1], distRight[1][0], distRight[1][1])) {
245 return true;
246 }
247
248 // Check left
249 if (not sameSign(distLeft[0][0], distLeft[0][1], distLeft[1][0], distLeft[1][1])) {
250 return true;
251 }
252
253 // Check the extremum
254 float rHitMinExtr = thetaVecMin.cross(pos2D);
255 float rHitMaxExtr = thetaVecMax.cross(pos2D);
256 if (rHitMinExtr * rHitMaxExtr < 0.) return checkExtremum(node, wireHit);
257
258 // Not contained
259 return false;
260}
bool checkDerivative(QuadTree *node, const TrackingUtilities::CDCWireHit *wireHit) const
Check derivative of the Legendre curve.
bool checkExtremum(QuadTree *node, const TrackingUtilities::CDCWireHit *wireHit) const
Checks whether extreme point is located within QuadTree node's ranges.

◆ isInNode() [2/2]

virtual bool isInNode ( QuadTree * node,
const TrackingUtilities::CDCWireHit * item ) const
protectedpure virtualinherited

Implement that function if you want to provide a new processor.

It is called when filling the quad tree after creation. For every item in a node and every child node this function gets called and should decide, if the item should go into this child node or not.

Parameters
nodechild node
itemitem to be filled into the child node or not
Returns
true if this item belongs into this node.

◆ isLeaf() [1/2]

bool isLeaf ( QuadTree * node) const
finalprotected

lastLevel depends on curvature of the track candidate

Definition at line 121 of file AxialHitQuadTreeProcessor.cc.

122{
123 if (node->getLevel() <= 6) return false;
124 if (node->getLevel() >= getLastLevel()) return true;
125
126 const double nodeResolution = fabs(node->getYMin() - node->getYMax());
127 const double meanCurv = (node->getYMax() + node->getYMin()) / 2;
128
129 const double resolution = m_precisionFunction(meanCurv);
130 if (resolution >= nodeResolution) return true;
131
132 return false;
133}

◆ isLeaf() [2/2]

virtual bool isLeaf ( QuadTree * node) const
inlineprotectedvirtualinherited

Function which checks if given node is leaf Implemented as virtual to keep possibility of changing lastLevel values depending on region is phase-space (i.e.

setting lastLevel as a function of Y-variable)

Definition at line 370 of file QuadTreeProcessor.h.

371 {
372 if (node->getLevel() >= m_lastLevel) {
373 return true;
374 } else {
375 return false;
376 }
377 }

◆ seed()

void seed ( const std::vector< const TrackingUtilities::CDCWireHit * > & datas)
inlineinherited

Fill in the items in the given vector.

They are transformed to QuadTreeItems internally.

Definition at line 113 of file QuadTreeProcessor.h.

114 {
115 // Create the items
116 for (AData* data : datas) {
117 m_items.emplace_back(data);
118 }
119
120 // Creating the seed level
121 long nSeedBins = pow(2, m_seedLevel);
122 m_seededTrees.reserve(nSeedBins * nSeedBins);
123
124 // Expand the first levels to the seed sectors
125 m_seededTrees.push_back(m_quadTree.get());
126 std::vector<QuadTree*> nextSeededTrees;
127
128 for (int level = 0; level < m_seedLevel; ++level) {
129 for (QuadTree* node : m_seededTrees) {
130 if (node->getChildren().empty()) {
131 this->createChildren(node, node->getChildren());
132 }
133 for (QuadTree& child : node->getChildren()) {
134 nextSeededTrees.push_back(&child);
135 }
136 }
137 std::swap(nextSeededTrees, m_seededTrees);
138 nextSeededTrees.clear();
139 }
140
141 // Fill the seed level with the items
142 m_itemPtrs.clear();
143 m_itemPtrs.reserve(m_items.size());
144 for (Item& item : m_items) {
145 m_itemPtrs.push_back(&item);
146 }
147
148 for (QuadTree* seededTree : m_seededTrees) {
149 seededTree->reserveItems(m_items.size());
150 }
151
152 this->insertItemsInNodes(m_seededTrees, m_itemPtrs);
153 }

Member Data Documentation

◆ c_curlCurv

const double c_curlCurv = 0.02
private

The curvature above which the trajectory is considered a curler.

Definition at line 202 of file AxialHitQuadTreeProcessor.h.

◆ c_maxNChildren

const int c_maxNChildren
staticprivateinherited

Upper bound on the number of children of a node - they are kept on the stack.

Definition at line 47 of file QuadTreeProcessor.h.

◆ m_childPtrs

std::vector<QuadTree*> m_childPtrs
protectedinherited

Reusable buffer with pointers to the children of the node currently being filled.

Definition at line 420 of file QuadTreeProcessor.h.

◆ m_cosSinLookupTable

const TrackingUtilities::LookupTable<TrackingUtilities::Vector2D>* m_cosSinLookupTable
private

Pinned lookup table for precomputed cosine and sine values.

Definition at line 199 of file AxialHitQuadTreeProcessor.h.

◆ m_debugOutput

bool m_debugOutput
privateinherited

A flag to control the creation of the debug output.

Definition at line 437 of file QuadTreeProcessor.h.

◆ m_debugOutputMap

std::map<std::pair<long, float>, std::vector<Item*> > m_debugOutputMap
privateinherited

The calculated debug map.

Definition at line 440 of file QuadTreeProcessor.h.

◆ m_itemPtrs

std::vector<Item*> m_itemPtrs
protectedinherited

Reusable buffer with pointers to all items - used to seed the tree.

Definition at line 417 of file QuadTreeProcessor.h.

◆ m_items

std::deque<Item> m_items
protectedinherited

Storage space for the items that are referenced by the quad tree nodes.

Definition at line 414 of file QuadTreeProcessor.h.

◆ m_lastLevel

int m_lastLevel
privateinherited

The last level to be filled.

Definition at line 431 of file QuadTreeProcessor.h.

◆ m_localOrigin

TrackingUtilities::Vector2D m_localOrigin
private

Local origin on which the phase space coordinates are centered.

Definition at line 196 of file AxialHitQuadTreeProcessor.h.

◆ m_nodeCaches

std::vector<NodeCache> m_nodeCaches
private

Reusable buffer with the per node quantities - one entry per node.

Definition at line 189 of file AxialHitQuadTreeProcessor.h.

◆ m_precisionFunction

PrecisionUtil::PrecisionFunction m_precisionFunction
private

Lambda which holds resolution function for the quadtree.

Definition at line 193 of file AxialHitQuadTreeProcessor.h.

◆ m_quadTree

std::unique_ptr<QuadTree> m_quadTree
protectedinherited

The quad tree we work with.

Definition at line 411 of file QuadTreeProcessor.h.

◆ m_seededTrees

std::vector<QuadTree*> m_seededTrees
protectedinherited

Vector of QuadTrees QuadTree instances (which are filled in the vector) cover the whole Legendre phase-space; each instance is processes independently.

Definition at line 427 of file QuadTreeProcessor.h.

◆ m_seedLevel

int m_seedLevel
privateinherited

The first level to be filled, effectively skip forward to this higher granularity level.

Definition at line 434 of file QuadTreeProcessor.h.

◆ m_thetaSpanCaches

std::vector<ThetaSpanCache> m_thetaSpanCaches
private

Reusable buffer with the per theta span quantities - one entry per distinct theta span.

Definition at line 186 of file AxialHitQuadTreeProcessor.h.

◆ m_twoSidedPhaseSpace

bool m_twoSidedPhaseSpace
private

Indicator whether the two sided phases space insertion check should be used This option should automatically split back to back tracks in the low curvature regions.

Definition at line 208 of file AxialHitQuadTreeProcessor.h.


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