Belle II Software development
AxialHitQuadTreeProcessor.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8#include <tracking/trackFindingCDC/legendre/quadtree/AxialHitQuadTreeProcessor.h>
9
10#include <tracking/trackingUtilities/eventdata/hits/CDCWireHit.h>
11#include <tracking/trackingUtilities/geometry/VectorUtil.h>
12
13#include <array>
14#include <vector>
15
16#include <Math/Vector2D.h>
17#include <TF1.h>
18#include <TCanvas.h>
19#include <TGraph.h>
20#include <TAxis.h>
21
22using namespace Belle2;
23using namespace TrackFindingCDC;
24using namespace TrackingUtilities;
25
26namespace {
27 bool sameSign(double n1, double n2, double n3, double n4)
28 {
29 return ((n1 > 0 && n2 > 0 && n3 > 0 && n4 > 0) || (n1 < 0 && n2 < 0 && n3 < 0 && n4 < 0));
30 }
31
32 using YSpan = AxialHitQuadTreeProcessor::YSpan;
33 YSpan splitCurvSpan(const YSpan& curvSpan, int nodeLevel, int lastLevel, int j)
34 {
35 const float meanCurv = curvSpan[0] + (curvSpan[1] - curvSpan[0]) / 2.0;
36 const std::array<float, 3> binBounds{curvSpan[0], meanCurv, curvSpan[1]};
37 const float binWidth = binBounds[j + 1] - binBounds[j];
38
39 const bool standardBinning = (nodeLevel <= lastLevel - 7) or (std::fabs(meanCurv) <= 0.005);
40 if (standardBinning) {
41 // B2INFO("Case 1* " << meanCurv << " " << (meanCurv <= 0.005));
42 float curv1 = binBounds[j];
43 float curv2 = binBounds[j + 1];
44
45 // Standard bin division
46 return {curv1, curv2};
47 }
48
49 // Non-standard binning
50 // For level 6 to 7 only expand 1 / 4, for higher levels expand 1 / 8.
51 // (assuming last level == 12)
52 if (nodeLevel < lastLevel - 5) {
53 // B2INFO("Case 2*");
54 float curv1 = binBounds[j] - binWidth / 4.;
55 float curv2 = binBounds[j + 1] + binWidth / 4.;
56 return {curv1, curv2};
57 } else {
58 // B2INFO("Case 3*");
59 float curv1 = binBounds[j] - binWidth / 8.;
60 float curv2 = binBounds[j + 1] + binWidth / 8.;
61 return {curv1, curv2};
62 }
63 }
64
65}
66
67std::vector<float> AxialHitQuadTreeProcessor::createCurvBound(YSpan curvSpan, int lastLevel)
68{
69 std::vector<YSpan> spans{{curvSpan}};
70
71 std::vector<YSpan> nextSpans;
72 for (int level = 1; level <= lastLevel; ++level) {
73 nextSpans.clear();
74 for (const YSpan& span : spans) {
75 nextSpans.push_back(splitCurvSpan(span, level, lastLevel, 0));
76 nextSpans.push_back(splitCurvSpan(span, level, lastLevel, 1));
77 }
78 spans.swap(nextSpans);
79 }
80
81 std::vector<float> bounds;
82 for (const YSpan& span : spans) {
83 bounds.push_back(span[0]);
84 bounds.push_back(span[1]);
85 }
86
87 assert(bounds.size() == std::pow(2, lastLevel));
88 return bounds;
89}
90
92{
93 static const int maxLevel = PrecisionUtil::getLookupGridLevel();
94 static const int nBins = std::pow(2, maxLevel);
95 static LookupTable<ROOT::Math::XYVector> trigonometricLookUpTable(&VectorUtil::Phi, nBins, -M_PI, M_PI);
96 return trigonometricLookUpTable;
97}
98
100 int seedLevel,
101 const XYSpans& ranges,
102 PrecisionUtil::PrecisionFunction precisionFunction)
103 : QuadTreeProcessor(lastLevel, seedLevel, ranges)
104 , m_precisionFunction(precisionFunction)
105 , m_localOrigin(0.0, 0.0)
107{
108 m_twoSidedPhaseSpace = m_quadTree->getYMin() * m_quadTree->getYMax() < 0;
109}
110
111AxialHitQuadTreeProcessor::AxialHitQuadTreeProcessor(const ROOT::Math::XYVector& localOrigin,
112 const YSpan& curvSpan,
113 const LookupTable<ROOT::Math::XYVector>* cosSinLookupTable)
114 : QuadTreeProcessor(0, 0, { {0, cosSinLookupTable->getNPoints() - 1}, curvSpan})
115, m_localOrigin(localOrigin)
116, m_cosSinLookupTable(cosSinLookupTable)
117{
118 // Never use two sided mode in off origin extension
119 m_twoSidedPhaseSpace = false;
120}
121
122
124{
125 if (node->getLevel() <= 6) return false;
126 if (node->getLevel() >= getLastLevel()) return true;
127
128 const double nodeResolution = fabs(node->getYMin() - node->getYMax());
129 const double meanCurv = (node->getYMax() + node->getYMin()) / 2;
130
131 const double resolution = m_precisionFunction(meanCurv);
132 if (resolution >= nodeResolution) return true;
133
134 return false;
135}
136
139{
140 const int nodeLevel = node->getLevel();
141 const int lastLevel = getLastLevel();
142 const float meanCurv = std::fabs(node->getYMax() + node->getYMin()) / 2;
143
144 // Expand bins for all nodes 7 levels before the last level (for lastLevel = 12 starting at 6)
145 // but only in a curvature region higher than 0.005. Lower than that use always standard.
146 bool standardBinning = (nodeLevel <= lastLevel - 7) or (meanCurv <= 0.005);
147
148 if (standardBinning) {
149 float r1 = node->getYLowerBound(j);
150 float r2 = node->getYUpperBound(j);
151 long theta1 = node->getXLowerBound(i);
152 long theta2 = node->getXUpperBound(i);
153
154 // Standard bin division
155 return XYSpans({theta1, theta2}, {r1, r2});
156 }
157
158 // Non-standard binning
159 // For level 6 to 7 only expand 1 / 4, for higher levels expand 1 / 8.
160 // (assuming last level == 12)
161 if (nodeLevel < lastLevel - 5) {
162 float r1 = node->getYLowerBound(j) - node->getYBinWidth(j) / 4.;
163 float r2 = node->getYUpperBound(j) + node->getYBinWidth(j) / 4.;
164
165 // long extension = pow(2, lastLevel - nodeLevel) / 4; is same as:
166 long extension = pow(2, lastLevel - nodeLevel - 2);
167
168 long theta1 = node->getXLowerBound(i) - extension;
169 if (theta1 < 0) theta1 = 0;
170
171 long theta2 = node->getXUpperBound(i) + extension;
172 if (theta2 >= m_cosSinLookupTable->getNPoints()) {
173 theta2 = m_cosSinLookupTable->getNPoints() - 1;
174 }
175
176 return XYSpans({theta1, theta2}, {r1, r2});
177 } else {
178 float r1 = node->getYLowerBound(j) - node->getYBinWidth(j) / 8.;
179 float r2 = node->getYUpperBound(j) + node->getYBinWidth(j) / 8.;
180
181 // long extension = pow(2, lastLevel - nodeLevel) / 8; is same as
182 long extension = pow(2, lastLevel - nodeLevel - 3);
183
184 long theta1 = node->getXLowerBound(i) - extension;
185 if (theta1 < 0) theta1 = 0;
186
187 long theta2 = node->getXUpperBound(i) + extension;
188 if (theta2 >= m_cosSinLookupTable->getNPoints()) {
189 theta2 = m_cosSinLookupTable->getNPoints() - 1;
190 }
191
192 return XYSpans({theta1, theta2}, {r1, r2});
193 }
194}
195
197{
198 // Check whether the hit lies in the forward direction
199 if (node->getLevel() <= 4 and m_twoSidedPhaseSpace and node->getYMin() > -c_curlCurv and
200 node->getYMax() < c_curlCurv) {
201 if (not checkDerivative(node, wireHit)) return false;
202 }
203
204 const double& driftLength = wireHit->getRefDriftLength();
205 const ROOT::Math::XYVector& pos2D = wireHit->getRefPos2D() - m_localOrigin;
206 double r2 = pos2D.Mag2() - driftLength * driftLength;
207
208 using Quadlet = std::array<std::array<float, 2>, 2>;
209 Quadlet distRight{};
210 Quadlet distLeft{};
211
212 // get top and bottom borders of the node
213 float rMin = node->getYMin() * r2 / 2;
214 float rMax = node->getYMax() * r2 / 2;
215
216 // get left and right borders of the node
217 long thetaMin = node->getXMin();
218 long thetaMax = node->getXMax();
219
220 const ROOT::Math::XYVector& thetaVecMin = m_cosSinLookupTable->at(thetaMin);
221 const ROOT::Math::XYVector& thetaVecMax = m_cosSinLookupTable->at(thetaMax);
222
223 float rHitMin = thetaVecMin.Dot(pos2D);
224 float rHitMax = thetaVecMax.Dot(pos2D);
225
226 // compute Legendre curves at the left and right borders of the node
227 float rHitMinRight = rHitMin - driftLength;
228 float rHitMaxRight = rHitMax - driftLength;
229
230 float rHitMinLeft = rHitMin + driftLength;
231 float rHitMaxLeft = rHitMax + driftLength;
232
233 // Compute distance from the Legendre curves to bottom and top borders of the node
234 distRight[0][0] = rMin - rHitMinRight;
235 distRight[0][1] = rMin - rHitMaxRight;
236 distRight[1][0] = rMax - rHitMinRight;
237 distRight[1][1] = rMax - rHitMaxRight;
238
239 distLeft[0][0] = rMin - rHitMinLeft;
240 distLeft[0][1] = rMin - rHitMaxLeft;
241 distLeft[1][0] = rMax - rHitMinLeft;
242 distLeft[1][1] = rMax - rHitMaxLeft;
243
244 // Compare distance signs from Legendre curves to the node
245 // Check right
246 if (not sameSign(distRight[0][0], distRight[0][1], distRight[1][0], distRight[1][1])) {
247 return true;
248 }
249
250 // Check left
251 if (not sameSign(distLeft[0][0], distLeft[0][1], distLeft[1][0], distLeft[1][1])) {
252 return true;
253 }
254
255 // Check the extremum
256 float rHitMinExtr = VectorUtil::Cross(thetaVecMin, pos2D);
257 float rHitMaxExtr = VectorUtil::Cross(thetaVecMax, pos2D);
258 if (rHitMinExtr * rHitMaxExtr < 0.) return checkExtremum(node, wireHit);
259
260 // Not contained
261 return false;
262}
263
264void AxialHitQuadTreeProcessor::insertItemsInNodes(const std::vector<QuadTree*>& nodes,
265 const std::vector<Item*>& items)
266{
267 const size_t nNodes = nodes.size();
268 if (nNodes == 0 or items.empty()) return;
269
270 // Collect the geometry of the nodes and group them by their theta span.
271 // The nodes handed here are either the four children of one node or the nodes of the seed
272 // level, which both cover only a handful of distinct theta spans.
273 m_thetaSpanCaches.clear();
274 m_nodeCaches.resize(nNodes);
275
276 for (size_t iNode = 0; iNode < nNodes; ++iNode) {
277 QuadTree* node = nodes[iNode];
278 NodeCache& nodeCache = m_nodeCaches[iNode];
279 nodeCache.yMin = node->getYMin();
280 nodeCache.yMax = node->getYMax();
281 nodeCache.needsDerivativeCheck = node->getLevel() <= 4 and m_twoSidedPhaseSpace and
282 nodeCache.yMin > -c_curlCurv and nodeCache.yMax < c_curlCurv;
283
284 const long xMin = node->getXMin();
285 const long xMax = node->getXMax();
286
287 size_t iThetaSpan = 0;
288 for (; iThetaSpan < m_thetaSpanCaches.size(); ++iThetaSpan) {
289 if (m_thetaSpanCaches[iThetaSpan].xMin == xMin and m_thetaSpanCaches[iThetaSpan].xMax == xMax) break;
290 }
291 if (iThetaSpan == m_thetaSpanCaches.size()) {
292 ThetaSpanCache thetaSpanCache;
293 thetaSpanCache.xMin = xMin;
294 thetaSpanCache.xMax = xMax;
295 thetaSpanCache.thetaVecMin = &m_cosSinLookupTable->at(xMin);
296 thetaSpanCache.thetaVecMax = &m_cosSinLookupTable->at(xMax);
297 m_thetaSpanCaches.push_back(thetaSpanCache);
298 }
299 nodeCache.iThetaSpan = iThetaSpan;
300 }
301
302 const size_t nThetaSpans = m_thetaSpanCaches.size();
303
304 for (Item* item : items) {
305 if (item->isUsed()) continue;
306
307 const CDCWireHit* wireHit = item->getPointer();
308
309 // Quantities that only depend on the hit
310 const double driftLength = wireHit->getRefDriftLength();
311 const ROOT::Math::XYVector pos2D = wireHit->getRefPos2D() - m_localOrigin;
312 const double r2 = pos2D.Mag2() - driftLength * driftLength;
313
314 // Quantities that only depend on the hit and the theta span of a node
315 for (size_t iThetaSpan = 0; iThetaSpan < nThetaSpans; ++iThetaSpan) {
316 ThetaSpanCache& thetaSpanCache = m_thetaSpanCaches[iThetaSpan];
317 const ROOT::Math::XYVector& thetaVecMin = *thetaSpanCache.thetaVecMin;
318 const ROOT::Math::XYVector& thetaVecMax = *thetaSpanCache.thetaVecMax;
319
320 const float rHitMin = thetaVecMin.Dot(pos2D);
321 const float rHitMax = thetaVecMax.Dot(pos2D);
322
323 thetaSpanCache.rHitMinRight = rHitMin - driftLength;
324 thetaSpanCache.rHitMaxRight = rHitMax - driftLength;
325 thetaSpanCache.rHitMinLeft = rHitMin + driftLength;
326 thetaSpanCache.rHitMaxLeft = rHitMax + driftLength;
327
328 const float rHitMinExtr = VectorUtil::Cross(thetaVecMin, pos2D);
329 const float rHitMaxExtr = VectorUtil::Cross(thetaVecMax, pos2D);
330 thetaSpanCache.rHitMinExtr = rHitMinExtr;
331 thetaSpanCache.rHitMaxExtr = rHitMaxExtr;
332
333 // Same decision as checkDerivative()
334 thetaSpanCache.derivativeOk = ((rHitMinExtr > 0) and (rHitMaxExtr * rHitMinExtr >= 0)) or
335 (rHitMaxExtr * rHitMinExtr < 0);
336
337 thetaSpanCache.hasExtremum = rHitMinExtr * rHitMaxExtr < 0.;
338 if (thetaSpanCache.hasExtremum) {
339 thetaSpanCache.extremumIsBetween = VectorUtil::isBetween(pos2D, thetaVecMin, thetaVecMax);
340 }
341 }
342
343 // Legendre curves at the extremum - only needed if some theta span contains the extremum
344 bool extremumComputed = false;
345 float rRight = 0;
346 float rLeft = 0;
347
348 for (size_t iNode = 0; iNode < nNodes; ++iNode) {
349 const NodeCache& nodeCache = m_nodeCaches[iNode];
350 const ThetaSpanCache& thetaSpanCache = m_thetaSpanCaches[nodeCache.iThetaSpan];
351
352 // Check whether the hit lies in the forward direction
353 if (nodeCache.needsDerivativeCheck and not thetaSpanCache.derivativeOk) continue;
354
355 // get top and bottom borders of the node
356 const float rMin = nodeCache.yMin * r2 / 2;
357 const float rMax = nodeCache.yMax * r2 / 2;
358
359 // Compare distance signs from the Legendre curves to the node
360 // Check right
361 if (not sameSign(rMin - thetaSpanCache.rHitMinRight,
362 rMin - thetaSpanCache.rHitMaxRight,
363 rMax - thetaSpanCache.rHitMinRight,
364 rMax - thetaSpanCache.rHitMaxRight)) {
365 nodes[iNode]->insertItem(item);
366 continue;
367 }
368
369 // Check left
370 if (not sameSign(rMin - thetaSpanCache.rHitMinLeft,
371 rMin - thetaSpanCache.rHitMaxLeft,
372 rMax - thetaSpanCache.rHitMinLeft,
373 rMax - thetaSpanCache.rHitMaxLeft)) {
374 nodes[iNode]->insertItem(item);
375 continue;
376 }
377
378 // Check the extremum
379 if (not thetaSpanCache.hasExtremum) continue;
380 if (not thetaSpanCache.extremumIsBetween) continue;
381
382 if (not extremumComputed) {
383 const double r = pos2D.R();
384 rRight = r - driftLength;
385 rLeft = r + driftLength;
386 extremumComputed = true;
387 }
388
389 const bool crossesRight = (rMin - rRight) * (rMax - rRight) < 0;
390 const bool crossesLeft = (rMin - rLeft) * (rMax - rLeft) < 0;
391 if (crossesRight or crossesLeft) {
392 nodes[iNode]->insertItem(item);
393 }
394 }
395 }
396}
397
399{
400 const ROOT::Math::XYVector& pos2D = wireHit->getRefPos2D() - m_localOrigin;
401
402 long thetaMin = node->getXMin();
403 long thetaMax = node->getXMax();
404
405 const ROOT::Math::XYVector& thetaVecMin = m_cosSinLookupTable->at(thetaMin);
406 const ROOT::Math::XYVector& thetaVecMax = m_cosSinLookupTable->at(thetaMax);
407
408 float rMinD = VectorUtil::Cross(thetaVecMin, pos2D);
409 float rMaxD = VectorUtil::Cross(thetaVecMax, pos2D);
410
411 // Does not really make sense...
412 if ((rMinD > 0) && (rMaxD * rMinD >= 0)) return true;
413 if ((rMaxD * rMinD < 0)) return true;
414 return false;
415}
416
418{
419 const double& driftLength = wireHit->getRefDriftLength();
420 const ROOT::Math::XYVector& pos2D = wireHit->getRefPos2D() - m_localOrigin;
421 double r2 = pos2D.Mag2() - driftLength * driftLength;
422
423 // get left and right borders of the node
424 long thetaMin = node->getXMin();
425 long thetaMax = node->getXMax();
426
427 const ROOT::Math::XYVector& thetaVecMin = m_cosSinLookupTable->at(thetaMin);
428 const ROOT::Math::XYVector& thetaVecMax = m_cosSinLookupTable->at(thetaMax);
429
430 if (not VectorUtil::isBetween(pos2D, thetaVecMin, thetaVecMax)) return false;
431
432 // compute Legendre curves at the position
433 double r = pos2D.R();
434 float rRight = r - driftLength;
435 float rLeft = r + driftLength;
436
437 // get top and bottom borders of the node
438 float rMin = node->getYMin() * r2 / 2;
439 float rMax = node->getYMax() * r2 / 2;
440
441 bool crossesRight = (rMin - rRight) * (rMax - rRight) < 0;
442 bool crossesLeft = (rMin - rLeft) * (rMax - rLeft) < 0;
443 return crossesRight or crossesLeft;
444}
445
446void AxialHitQuadTreeProcessor::drawHits(const std::vector<const CDCWireHit*>& hits, unsigned int color) const
447{
448 static int nevent(0);
449
450 TCanvas* canv = new TCanvas("canv", "legendre transform", 0, 0, 1200, 600);
451 canv->cd(1);
452 TGraph* dummyGraph = new TGraph();
453 dummyGraph->SetPoint(1, -M_PI, 0);
454 dummyGraph->SetPoint(2, M_PI, 0);
455 dummyGraph->Draw("AP");
456 dummyGraph->GetXaxis()->SetTitle("#theta");
457 dummyGraph->GetYaxis()->SetTitle("#rho");
458 dummyGraph->GetXaxis()->SetRangeUser(-M_PI, M_PI);
459 dummyGraph->GetYaxis()->SetRangeUser(-0.02, 0.15);
460
461 for (const CDCWireHit* wireHit : hits) {
462 const double& driftLength = wireHit->getRefDriftLength();
463 const ROOT::Math::XYVector& pos2D = wireHit->getRefPos2D() - m_localOrigin;
464 double x = pos2D.x();
465 double y = pos2D.y();
466 double r2 = pos2D.Mag2() - driftLength * driftLength;
467
468 TF1* concaveHitLegendre = new TF1("concaveHitLegendre", "2*([0]/[3])*cos(x) + 2*([1]/[3])*sin(x) + 2*([2]/[3])", -M_PI, M_PI);
469 TF1* convexHitLegendre = new TF1("convexHitLegendre", "2*([0]/[3])*cos(x) + 2*([1]/[3])*sin(x) - 2*([2]/[3])", -M_PI, M_PI);
470 concaveHitLegendre->SetLineWidth(1);
471 convexHitLegendre->SetLineWidth(1);
472 concaveHitLegendre->SetLineColor(color);
473 convexHitLegendre->SetLineColor(color);
474
475 concaveHitLegendre->SetParameters(x, y, driftLength, r2);
476 convexHitLegendre->SetParameters(x, y, driftLength, r2);
477 concaveHitLegendre->Draw("CSAME");
478 convexHitLegendre->Draw("CSAME");
479 }
480// canv->Print(Form("legendreHits_%i.root", nevent));
481// canv->Print(Form("legendreHits_%i.eps", nevent));
482 canv->Print(Form("legendreHits_%i.png", nevent));
483 delete canv;
484
485 nevent++;
486}
487
489{
490 std::vector<const CDCWireHit*> hits;
491 for (Item* item : node->getItems()) {
492 const CDCWireHit* wireHit = item->getPointer();
493 hits.push_back(wireHit);
494 }
495 drawHits(hits);
496}
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...
std::vector< ThetaSpanCache > m_thetaSpanCaches
Reusable buffer with the per theta span quantities - one entry per distinct theta span.
XYSpans createChild(QuadTree *node, int i, int j) const final
Return the new ranges.
ROOT::Math::XYVector m_localOrigin
Local origin on which the phase space coordinates are centered.
const double c_curlCurv
The curvature above which the trajectory is considered a curler.
const TrackingUtilities::LookupTable< ROOT::Math::XYVector > * m_cosSinLookupTable
Pinned lookup table for precomputed cosine and sine values.
bool m_twoSidedPhaseSpace
Indicator whether the two sided phases space insertion check should be used This option should automa...
bool checkDerivative(QuadTree *node, const TrackingUtilities::CDCWireHit *wireHit) const
Check derivative of the Legendre curve.
bool isLeaf(QuadTree *node) const final
lastLevel depends on curvature of the track candidate
void drawHits(const std::vector< const TrackingUtilities::CDCWireHit * > &hits, unsigned int color=46) const
Draw QuadTree node.
bool isInNode(QuadTree *node, const TrackingUtilities::CDCWireHit *wireHit) const final
Check whether hit belongs to the quadtree node:
bool checkExtremum(QuadTree *node, const TrackingUtilities::CDCWireHit *wireHit) const
Checks whether extreme point is located within QuadTree node's ranges.
AxialHitQuadTreeProcessor(int lastLevel, int seedLevel, const XYSpans &ranges, PrecisionUtil::PrecisionFunction precisionFunction)
Constructor.
PrecisionUtil::PrecisionFunction m_precisionFunction
Lambda which holds resolution function for the quadtree.
std::vector< NodeCache > m_nodeCaches
Reusable buffer with the per node quantities - one entry per node.
void drawNode(QuadTree *node) const
Draw QuadTree node.
static const TrackingUtilities::LookupTable< ROOT::Math::XYVector > & 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.
static constexpr int getLookupGridLevel()
Returns desired deepness of the trigonometrical lookup table. Used as template parameter for the Trig...
std::function< double(double)> PrecisionFunction
Function type which is used for resolution calculations (resolution=f(curvature)) Takes a curvature v...
std::vector< AItem * > & getItems()
Get items from node.
AY getYBinWidth(int iBin)
Getter for the width of the iBin bin in "r" direction.
AX getXMax() const
Get maximal "Theta" value of the node.
AY getYMax() const
Get maximal "r" value of the node.
AY getYMin() const
Get minimal "r" value of the node.
int getLevel() const
Returns level of the node in tree (i.e., how much ancestors the node has)
AX getXLowerBound(int iBin) const
Get lower "Theta" value of given bin.
AY getYUpperBound(int iBin) const
Get upper "r" value of given bin.
AY getYLowerBound(int iBin) const
Get lower "r" value of given bin.
AX getXMin() const
Get minimal "Theta" value of the node.
AX getXUpperBound(int iBin) const
Get upper "Theta" value of given bin.
QuadTreeProcessor(int lastLevel, int seedLevel, const XYSpans &xySpans, bool debugOutput=false)
Class representing a hit wire in the central drift chamber.
Definition CDCWireHit.h:56
Class which holds precomputed values of a function.
Definition LookupTable.h:50
int getNPoints() const
Return the number of finite sampling points in this lookup table.
bool sameSign(double expected, double actual)
Predicate checking that two values have the same sign.
Abstract base class for different kinds of events.
Geometry of a node that is needed in the containment check.
int iThetaSpan
Index of the theta span of the node in the theta span cache.
bool needsDerivativeCheck
Indicator that the forward direction of the hit has to be checked for this node.
Quantities entering the node containment check that only depend on the hit and on the theta span of a...
bool extremumIsBetween
Indicator that the extremum is a candidate for the containment check.
float rHitMaxRight
Legendre curve of the right passage hypothesis at the upper theta bound.
long xMin
Lower theta bound of the nodes in this group as an index into the lookup table.
float rHitMaxExtr
Derivative of the Legendre curve at the upper theta bound.
float rHitMinExtr
Derivative of the Legendre curve at the lower theta bound.
bool hasExtremum
Indicator that the extremum of the Legendre curve lies within this theta span.
const ROOT::Math::XYVector * thetaVecMin
Unit vector (cos, sin) at the lower theta bound.
long xMax
Upper theta bound of the nodes in this group as an index into the lookup table.
const ROOT::Math::XYVector * thetaVecMax
Unit vector (cos, sin) at the upper theta bound.
float rHitMinRight
Legendre curve of the right passage hypothesis at the lower theta bound.
bool derivativeOk
Result of the derivative check for this theta span.
float rHitMaxLeft
Legendre curve of the left passage hypothesis at the upper theta bound.
float rHitMinLeft
Legendre curve of the left passage hypothesis at the lower theta bound.