8#include <tracking/trackFindingCDC/legendre/quadtree/AxialHitQuadTreeProcessor.h>
10#include <tracking/trackingUtilities/eventdata/hits/CDCWireHit.h>
11#include <tracking/trackingUtilities/geometry/VectorUtil.h>
16#include <Math/Vector2D.h>
23using namespace TrackFindingCDC;
24using namespace TrackingUtilities;
27 bool sameSign(
double n1,
double n2,
double n3,
double n4)
29 return ((n1 > 0 && n2 > 0 && n3 > 0 && n4 > 0) || (n1 < 0 && n2 < 0 && n3 < 0 && n4 < 0));
32 using YSpan = AxialHitQuadTreeProcessor::YSpan;
33 YSpan splitCurvSpan(
const YSpan& curvSpan,
int nodeLevel,
int lastLevel,
int j)
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];
39 const bool standardBinning = (nodeLevel <= lastLevel - 7) or (std::fabs(meanCurv) <= 0.005);
40 if (standardBinning) {
42 float curv1 = binBounds[j];
43 float curv2 = binBounds[j + 1];
46 return {curv1, curv2};
52 if (nodeLevel < lastLevel - 5) {
54 float curv1 = binBounds[j] - binWidth / 4.;
55 float curv2 = binBounds[j + 1] + binWidth / 4.;
56 return {curv1, curv2};
59 float curv1 = binBounds[j] - binWidth / 8.;
60 float curv2 = binBounds[j + 1] + binWidth / 8.;
61 return {curv1, curv2};
69 std::vector<YSpan> spans{{curvSpan}};
71 std::vector<YSpan> nextSpans;
72 for (
int level = 1; level <= lastLevel; ++level) {
74 for (
const YSpan& span : spans) {
75 nextSpans.push_back(splitCurvSpan(span, level, lastLevel, 0));
76 nextSpans.push_back(splitCurvSpan(span, level, lastLevel, 1));
78 spans.swap(nextSpans);
81 std::vector<float> bounds;
82 for (
const YSpan& span : spans) {
83 bounds.push_back(span[0]);
84 bounds.push_back(span[1]);
87 assert(bounds.size() == std::pow(2, lastLevel));
94 static const int nBins = std::pow(2, maxLevel);
96 return trigonometricLookUpTable;
112 const YSpan& curvSpan,
115, m_localOrigin(localOrigin)
116, m_cosSinLookupTable(cosSinLookupTable)
119 m_twoSidedPhaseSpace =
false;
125 if (node->
getLevel() <= 6)
return false;
128 const double nodeResolution = fabs(node->
getYMin() - node->
getYMax());
132 if (resolution >= nodeResolution)
return true;
140 const int nodeLevel = node->
getLevel();
142 const float meanCurv = std::fabs(node->
getYMax() + node->
getYMin()) / 2;
146 bool standardBinning = (nodeLevel <= lastLevel - 7) or (meanCurv <= 0.005);
148 if (standardBinning) {
155 return XYSpans({theta1, theta2}, {r1, r2});
161 if (nodeLevel < lastLevel - 5) {
166 long extension = pow(2, lastLevel - nodeLevel - 2);
169 if (theta1 < 0) theta1 = 0;
176 return XYSpans({theta1, theta2}, {r1, r2});
182 long extension = pow(2, lastLevel - nodeLevel - 3);
185 if (theta1 < 0) theta1 = 0;
192 return XYSpans({theta1, theta2}, {r1, r2});
204 const double& driftLength = wireHit->getRefDriftLength();
205 const ROOT::Math::XYVector& pos2D = wireHit->getRefPos2D() -
m_localOrigin;
206 double r2 = pos2D.Mag2() - driftLength * driftLength;
208 using Quadlet = std::array<std::array<float, 2>, 2>;
213 float rMin = node->
getYMin() * r2 / 2;
214 float rMax = node->
getYMax() * r2 / 2;
217 long thetaMin = node->
getXMin();
218 long thetaMax = node->
getXMax();
223 float rHitMin = thetaVecMin.Dot(pos2D);
224 float rHitMax = thetaVecMax.Dot(pos2D);
227 float rHitMinRight = rHitMin - driftLength;
228 float rHitMaxRight = rHitMax - driftLength;
230 float rHitMinLeft = rHitMin + driftLength;
231 float rHitMaxLeft = rHitMax + driftLength;
234 distRight[0][0] = rMin - rHitMinRight;
235 distRight[0][1] = rMin - rHitMaxRight;
236 distRight[1][0] = rMax - rHitMinRight;
237 distRight[1][1] = rMax - rHitMaxRight;
239 distLeft[0][0] = rMin - rHitMinLeft;
240 distLeft[0][1] = rMin - rHitMaxLeft;
241 distLeft[1][0] = rMax - rHitMinLeft;
242 distLeft[1][1] = rMax - rHitMaxLeft;
246 if (not sameSign(distRight[0][0], distRight[0][1], distRight[1][0], distRight[1][1])) {
251 if (not sameSign(distLeft[0][0], distLeft[0][1], distLeft[1][0], distLeft[1][1])) {
256 float rHitMinExtr = VectorUtil::Cross(thetaVecMin, pos2D);
257 float rHitMaxExtr = VectorUtil::Cross(thetaVecMax, pos2D);
258 if (rHitMinExtr * rHitMaxExtr < 0.)
return checkExtremum(node, wireHit);
265 const std::vector<Item*>& items)
267 const size_t nNodes = nodes.size();
268 if (nNodes == 0 or items.empty())
return;
276 for (
size_t iNode = 0; iNode < nNodes; ++iNode) {
284 const long xMin = node->
getXMin();
285 const long xMax = node->
getXMax();
287 size_t iThetaSpan = 0;
293 thetaSpanCache.
xMin = xMin;
294 thetaSpanCache.
xMax = xMax;
304 for (
Item* item : items) {
305 if (item->isUsed())
continue;
307 const CDCWireHit* wireHit = item->getPointer();
310 const double driftLength = wireHit->getRefDriftLength();
311 const ROOT::Math::XYVector pos2D = wireHit->getRefPos2D() -
m_localOrigin;
312 const double r2 = pos2D.Mag2() - driftLength * driftLength;
315 for (
size_t iThetaSpan = 0; iThetaSpan < nThetaSpans; ++iThetaSpan) {
317 const ROOT::Math::XYVector& thetaVecMin = *thetaSpanCache.
thetaVecMin;
318 const ROOT::Math::XYVector& thetaVecMax = *thetaSpanCache.
thetaVecMax;
320 const float rHitMin = thetaVecMin.Dot(pos2D);
321 const float rHitMax = thetaVecMax.Dot(pos2D);
325 thetaSpanCache.
rHitMinLeft = rHitMin + driftLength;
326 thetaSpanCache.
rHitMaxLeft = rHitMax + driftLength;
328 const float rHitMinExtr = VectorUtil::Cross(thetaVecMin, pos2D);
329 const float rHitMaxExtr = VectorUtil::Cross(thetaVecMax, pos2D);
334 thetaSpanCache.
derivativeOk = ((rHitMinExtr > 0) and (rHitMaxExtr * rHitMinExtr >= 0)) or
335 (rHitMaxExtr * rHitMinExtr < 0);
337 thetaSpanCache.
hasExtremum = rHitMinExtr * rHitMaxExtr < 0.;
339 thetaSpanCache.
extremumIsBetween = VectorUtil::isBetween(pos2D, thetaVecMin, thetaVecMax);
344 bool extremumComputed =
false;
348 for (
size_t iNode = 0; iNode < nNodes; ++iNode) {
356 const float rMin = nodeCache.
yMin * r2 / 2;
357 const float rMax = nodeCache.
yMax * r2 / 2;
365 nodes[iNode]->insertItem(item);
370 if (not sameSign(rMin - thetaSpanCache.
rHitMinLeft,
374 nodes[iNode]->insertItem(item);
382 if (not extremumComputed) {
383 const double r = pos2D.R();
384 rRight = r - driftLength;
385 rLeft = r + driftLength;
386 extremumComputed =
true;
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);
400 const ROOT::Math::XYVector& pos2D = wireHit->getRefPos2D() -
m_localOrigin;
402 long thetaMin = node->
getXMin();
403 long thetaMax = node->
getXMax();
408 float rMinD = VectorUtil::Cross(thetaVecMin, pos2D);
409 float rMaxD = VectorUtil::Cross(thetaVecMax, pos2D);
412 if ((rMinD > 0) && (rMaxD * rMinD >= 0))
return true;
413 if ((rMaxD * rMinD < 0))
return true;
419 const double& driftLength = wireHit->getRefDriftLength();
420 const ROOT::Math::XYVector& pos2D = wireHit->getRefPos2D() -
m_localOrigin;
421 double r2 = pos2D.Mag2() - driftLength * driftLength;
424 long thetaMin = node->
getXMin();
425 long thetaMax = node->
getXMax();
430 if (not VectorUtil::isBetween(pos2D, thetaVecMin, thetaVecMax))
return false;
433 double r = pos2D.R();
434 float rRight = r - driftLength;
435 float rLeft = r + driftLength;
438 float rMin = node->
getYMin() * r2 / 2;
439 float rMax = node->
getYMax() * r2 / 2;
441 bool crossesRight = (rMin - rRight) * (rMax - rRight) < 0;
442 bool crossesLeft = (rMin - rLeft) * (rMax - rLeft) < 0;
443 return crossesRight or crossesLeft;
448 static int nevent(0);
450 TCanvas* canv =
new TCanvas(
"canv",
"legendre transform", 0, 0, 1200, 600);
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);
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;
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);
475 concaveHitLegendre->SetParameters(x, y, driftLength, r2);
476 convexHitLegendre->SetParameters(x, y, driftLength, r2);
477 concaveHitLegendre->Draw(
"CSAME");
478 convexHitLegendre->Draw(
"CSAME");
482 canv->Print(Form(
"legendreHits_%i.png", nevent));
490 std::vector<const CDCWireHit*> hits;
492 const CDCWireHit* wireHit = item->getPointer();
493 hits.push_back(wireHit);
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.
QuadTreeNode< long, float, Item > QuadTree
std::pair< XSpan, YSpan > XYSpans
QuadTreeProcessor(int lastLevel, int seedLevel, const XYSpans &xySpans, bool debugOutput=false)
typename QuadTree::YSpan YSpan
QuadTreeItem< const TrackingUtilities::CDCWireHit > Item
std::unique_ptr< QuadTree > m_quadTree
Class representing a hit wire in the central drift chamber.
Class which holds precomputed values of a function.
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.
float yMax
Upper curvature bound of the node.
float yMin
Lower curvature bound of the 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.