Skip to content

Commit 1b05db5

Browse files
committed
Implement new doublet cut based on triplet radii
This commit adds a new cut to the doublet finding which is able to determine based on only the doublets if it is possible to find a third spacepoint which will form a seed within the required helix radius bounds. This is the cut discussed on the traccc Mattermost recently.
1 parent 9dff675 commit 1b05db5

File tree

2 files changed

+142
-4
lines changed

2 files changed

+142
-4
lines changed

core/include/traccc/seeding/detail/seeding_config.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ struct seedfinder_config {
9191
float maxScatteringAngle2 = 0;
9292
float pTPerHelixRadius = 0;
9393
float minHelixDiameter2 = 0;
94+
float minHelixRadius = 0;
9495
float pT2perRadius = 0;
9596

9697
// Multiplicator for the number of phi-bins. The minimum number of phi-bins
@@ -126,6 +127,7 @@ struct seedfinder_config {
126127

127128
pTPerHelixRadius = bFieldInZ;
128129
minHelixDiameter2 = std::pow(minPt * 2.f / pTPerHelixRadius, 2.f);
130+
minHelixRadius = std::sqrt(minHelixDiameter2) / 2.f;
129131

130132
// @TODO: This is definitely a bug because highland / pTPerHelixRadius
131133
// is in length unit

core/include/traccc/seeding/doublet_finding_helper.hpp

Lines changed: 140 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,146 @@ bool TRACCC_HOST_DEVICE doublet_finding_helper::isCompatible(
7272
// actually zOrigin * deltaR to avoid division by 0 statements
7373
zOrigin = sp1.z() * deltaR - sp1.radius() * cotTheta;
7474
}
75-
return ((deltaR < config.deltaRMax) && (deltaR > config.deltaRMin) &&
76-
(math::fabs(cotTheta) < config.cotThetaMax * deltaR) &&
77-
(zOrigin > config.collisionRegionMin * deltaR) &&
78-
(zOrigin < config.collisionRegionMax * deltaR));
75+
76+
if ((deltaR >= config.deltaRMax) || (deltaR <= config.deltaRMin) ||
77+
(math::fabs(cotTheta) >= config.cotThetaMax * deltaR) ||
78+
(zOrigin <= config.collisionRegionMin * deltaR) ||
79+
(zOrigin >= config.collisionRegionMax * deltaR)) {
80+
return false;
81+
}
82+
83+
/*
84+
* The following cut is capable of discriminating some doublets on the
85+
* basis that it is impossible to find a third spacepoint for the doublet
86+
* that will keep the resulting triplet inside the helix radius bound.
87+
* This explanation is enhanced with Geogebra commands with can be entered
88+
* into the application directly to provide a visual "proof" of why this
89+
* cut works.
90+
*
91+
* We will start by creating two spacepoints at arbitrary locations (they
92+
* can be moved as desired):
93+
*
94+
* ```
95+
* A = (2, 4)
96+
* B = (3, 12)
97+
* ```
98+
*
99+
* We will also define a radius $R$:
100+
*
101+
* ```
102+
* R = 10
103+
* ```
104+
*
105+
* Next, we consider the fact that two points and a radius define exactly
106+
* two circles through those points and with that radius. This makes sense
107+
* because three points (six degrees of freedom) precisely define a single
108+
* circle, and two points and a radius (five DoFs) define two circles. We
109+
* will construct those circles now, with the radius being the minimum
110+
* helix radius from the configuration.
111+
*
112+
* To find the midpoints of these circles, we will first find the
113+
* perpendicular bisector of points $A$ and $B$:
114+
*
115+
* ```
116+
* M = 0.5 * (A + B)
117+
* ```
118+
*/
119+
scalar midX = 0.5f * (sp1.x() + sp2.x());
120+
scalar midY = 0.5f * (sp1.y() + sp2.y());
121+
122+
/*
123+
* Then we will compute the slope of the perpendicular bisector:
124+
*
125+
* ```
126+
* s = (y(B) - y(A)) / (x(B) - x(A))
127+
* ```
128+
*/
129+
scalar slope = (sp2.y() - sp1.y()) / (sp2.x() - sp1.x());
130+
131+
/*
132+
* Next, we can simply place circle midpoints on our perpendicular
133+
* bisector, but we cannot simply use the radius $R$ as the distance from
134+
* the midpoint of $A$ and $B$, we have account for the length of the
135+
* sagitta:
136+
*
137+
* ```
138+
* dX = x(B) - x(A)
139+
* dY = y(B) - y(A)
140+
* dXY2 = dX * dX + dY * dY
141+
* q = sqrt(R * R - dXY2 / 4)
142+
* ```
143+
*/
144+
scalar deltaX = sp2.x() - sp1.x();
145+
scalar deltaY = sp2.y() - sp1.y();
146+
scalar deltaXY2 = deltaX * deltaX + deltaY * deltaY;
147+
scalar sagittaLength = math::sqrt(
148+
config.minHelixRadius * config.minHelixRadius - deltaXY2 / 4.f);
149+
150+
/*
151+
* We then compute the central angle between the points $A$, $B$, and the
152+
* midpoints of the circles we want to construct. Naively, this can be
153+
* done using the trigonomic functions:
154+
*
155+
* ```
156+
* theta = atan(1 / slope)
157+
* ```
158+
*
159+
* After which we can compute the delta between the midpoint of $A$ and
160+
* $B$ and the midpoints of our circles:
161+
*
162+
* ```
163+
* mdX = (R - q) * cos(theta)
164+
* mdY = (R - q) * sin(theta)
165+
* ```
166+
*
167+
* However, some trigonomy allows us to reduce this:
168+
*
169+
* ```
170+
* denom = sqrt((s * s + 1) / (s * s))
171+
* cosTheta = 1 / denom
172+
* sinTheta = -1 / (s * denom)
173+
* mdX = q * cosTheta
174+
* mdY = q * sinTheta
175+
* ```
176+
*/
177+
scalar denom = math::sqrt((slope * slope + 1) / (slope * slope));
178+
scalar cosCentralAngle = 1.f / denom;
179+
scalar sinCentralAngle = -1.f / (slope * denom);
180+
181+
scalar mpDeltaX = sagittaLength * cosCentralAngle;
182+
scalar mpDeltaY = sagittaLength * sinCentralAngle;
183+
184+
/*
185+
* We now easily find the midpoints of the required circles:
186+
*
187+
* ```
188+
* V = (x(M) + mdX, y(M) + mdY)
189+
* W = (x(M) - mdX, y(M) - mdY)
190+
* ```
191+
*/
192+
scalar mp1X = midX + mpDeltaX;
193+
scalar mp2X = midX - mpDeltaX;
194+
scalar mp1Y = midY + mpDeltaY;
195+
scalar mp2Y = midY - mpDeltaY;
196+
197+
/*
198+
* Finally, we compute the radii of the circles. The crucial intuition
199+
* here is that if either of the newly constructed circles _completely_
200+
* contain a circle of radius $R$ around the origin, then we can never
201+
* find a third spacepoint to complete the triplet. Thus, we compute the
202+
* radii. We leave them squared in the C++ code to avoid an unnecessary
203+
* square root.
204+
*/
205+
scalar mp1R2 = mp1X * mp1X + mp1Y * mp1Y;
206+
scalar mp2R2 = mp2X * mp2X + mp2Y * mp2Y;
207+
208+
if (math::min(mp1R2, mp2R2) <=
209+
((config.minHelixRadius - config.impactMax) *
210+
(config.minHelixRadius - config.impactMax))) {
211+
return false;
212+
}
213+
214+
return true;
79215
}
80216

81217
template <details::spacepoint_type otherSpType, typename T1, typename T2>

0 commit comments

Comments
 (0)