ATLAS Offline Software
Loading...
Searching...
No Matches
AnnulusBoundsPC.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
4
7#include <cmath>
8
9#include <iostream>
10
12 double maxR,
13 double phiMin,
14 double phiMax,
16 double phiAvg)
17 : m_minR(minR),
18 m_maxR(maxR),
22 m_phiAvg(phiAvg)
23{
24
25 m_boundValues.resize(7);
33
34 m_rotationStripPC = Eigen::Translation<double, 2>(Amg::Vector2D(0, -m_phiAvg));
35 m_translation = Eigen::Translation<double, 2>(m_moduleOrigin);
36
39
40 // we need the corner points of the module to do the inside
41 // checking, calculate them here once, they don't change
42
43 // find inner outter radius at edges in STRIP PC
44 auto circIx = [](double O_x, double O_y, double r, double phi)
45 -> Amg::Vector2D {
46 // _____________________________________________
47 // / 2 2 2 2 2 2
48 // O_x + O_y*m - \/ - O_x *m + 2*O_x*O_y*m - O_y + m *r + r
49 // x = --------------------------------------------------------------
50 // 2
51 // m + 1
52 //
53 // y = m*x
54 //
55 double m = std::tan(phi);
56 Amg::Vector2D dir(std::cos(phi), std::sin(phi));
57 double x1 = (O_x + O_y*m - std::sqrt(-std::pow(O_x, 2)*std::pow(m, 2) + 2*O_x*O_y*m - std::pow(O_y, 2) + std::pow(m, 2)*std::pow(r, 2) + std::pow(r, 2)))/(std::pow(m, 2) + 1);
58 double x2 = (O_x + O_y*m + std::sqrt(-std::pow(O_x, 2)*std::pow(m, 2) + 2*O_x*O_y*m - std::pow(O_y, 2) + std::pow(m, 2)*std::pow(r, 2) + std::pow(r, 2)))/(std::pow(m, 2) + 1);
59
60 Amg::Vector2D v1(x1, m*x1);
61 if(v1.dot(dir) > 0) return v1;
62 return {x2, m*x2};
63 };
64
65 // calculate corners in STRIP XY, keep them we need them for minDistance()
70
75
80}
81
82std::pair<Trk::AnnulusBoundsPC, double>
84{
85 auto [k_L, k_R, d_L, d_R] = annbo.getEdgeLines();
86
87 double O_x = (d_L - d_R) / (k_R - k_L);
88 double O_y = std::fma(O_x, k_L, d_L); // O_x * k_L + d_L
89 Amg::Vector2D originStripXY(-O_x, -O_y);
90
91 const auto& bounds = annbo.getBoundsValues();
92
93 double minR = bounds[AnnulusBounds::bv_minR];
94 double maxR = bounds[AnnulusBounds::bv_maxR];
95 double phi = bounds[AnnulusBounds::bv_phi];
96 double phiS = bounds[AnnulusBounds::bv_phiS];
97 double phiAvg = 0; // phiAvg is the bounds-internal local rotation. We don't want one
98
99 // phi is the total opening angle, set up symmetric phi bounds
100 double phiMax = phi/2.0;
101 double phiMin = -phiMax;
102
103 // need to rotate pi/2 to reproduce ABCartesian orientation, phiS so that phi=0 is center and symmetric
104 double phiShift = M_PI_2 - phiS;
105
106 // we need to rotate the origin into the bounds local coordinate system
107 Transform2D avgPhiRotation;
108 avgPhiRotation = Rotation2D(-phiShift);
109 Amg::Vector2D originStripXYRotated = avgPhiRotation * originStripXY;
110
111 AnnulusBoundsPC abpc(minR,
112 maxR,
113 phiMin,
114 phiMax,
115 originStripXYRotated,
116 phiAvg);
117
118 return std::make_pair(std::move(abpc), phiShift);
119}
120
121bool
122Trk::AnnulusBoundsPC::inside(const Amg::Vector2D& locpo, double tol1, double tol2) const
123{
124 // locpo is PC in STRIP SYSTEM
125 // need to perform internal rotation induced by m_phiAvg
126 Amg::Vector2D locpo_rotated = m_rotationStripPC * locpo;
127 double tolR = tol1;
128 double tolPhi = tol2;
129 double phiLoc = locpo_rotated[Trk::locPhi];
130 double rLoc = locpo_rotated[Trk::locR];
131
132 if (phiLoc < (m_phiMin - tolPhi) || phiLoc > (m_phiMax + tolPhi)) {
133 return false;
134 }
135
136 // calculate R in MODULE SYSTEM to evaluate R-bounds
137 if (tolR == 0.) {
138 // don't need R, can use R^2
139 double r_mod2 = m_shiftPC[Trk::locR]*m_shiftPC[Trk::locR]
140 + rLoc*rLoc + 2*m_shiftPC[Trk::locR]*rLoc * std::cos(phiLoc - m_shiftPC[Trk::locPhi]);
141
142 if (r_mod2 < m_minR*m_minR || r_mod2 > m_maxR*m_maxR) {
143 return false;
144 }
145 }
146 else {
147 // use R
148 double r_mod = std::sqrt(m_shiftPC[Trk::locR]*m_shiftPC[Trk::locR]
149 + rLoc*rLoc + 2*m_shiftPC[Trk::locR]*rLoc * cos(phiLoc - m_shiftPC[Trk::locPhi]));
150
151 if (r_mod < (m_minR - tolR) || r_mod > (m_maxR + tolR)) {
152 return false;
153 }
154 }
155
156 return true;
157}
158
159
160bool
162{
163
164 // locpo is PC in STRIP SYSTEM
165
166 if(bchk.bcType == BoundaryCheck::absolute) {
167 // unpack tolerances and use other methods
168 if(bchk.checkLoc1 && bchk.checkLoc2) {
169 return inside(locpo, bchk.toleranceLoc1, bchk.toleranceLoc2);
170 }
171 else {
172 if(bchk.checkLoc1) {
173 return insideLoc1(locpo, bchk.toleranceLoc1);
174 }
175 else /* bchk.checkLoc2 */ {
176 return insideLoc2(locpo, bchk.toleranceLoc2);
177 }
178 }
179 }
180 else {
181 // first check if inside. We don't need to look into the covariance if inside
182 if(inside(locpo)) {
183 return true;
184 }
185
186 // we need to rotated the locpo
187 Amg::Vector2D locpo_rotated = m_rotationStripPC * locpo;
188
189 // covariance is given in STRIP SYSTEM in PC
190 // we need to convert the covariance to the MODULE SYSTEM in PC
191 // via jacobian.
192 // The following transforms into STRIP XY, does the shift into MODULE XY,
193 // and then transforms into MODULE PC
194 double dphi = m_phiAvg;
195 double phi_strip = locpo_rotated[Trk::locPhi];
196 double r_strip = locpo_rotated[Trk::locR];
197 double O_x = m_shiftXY[Trk::locX];
198 double O_y = m_shiftXY[Trk::locY];
199
200 // For a transformation from cartesian into polar coordinates
201 //
202 // [ _________ ]
203 // [ / 2 2 ]
204 // [ \/ x + y ]
205 // [ r' ] [ ]
206 // v = [ ] = [ / y \]
207 // [phi'] [2*atan|----------------|]
208 // [ | _________|]
209 // [ | / 2 2 |]
210 // [ \x + \/ x + y /]
211 //
212 // Where x, y are polar coordinates that can be rotated by dPhi
213 //
214 // [x] [O_x + r*cos(dPhi - phi)]
215 // [ ] = [ ]
216 // [y] [O_y - r*sin(dPhi - phi)]
217 //
218 // The general jacobian is:
219 //
220 // [d d ]
221 // [--(f_x) --(f_x)]
222 // [dx dy ]
223 // Jgen = [ ]
224 // [d d ]
225 // [--(f_y) --(f_y)]
226 // [dx dy ]
227 //
228 // which means in this case:
229 //
230 // [ d d ]
231 // [ ----------(rMod) ---------(rMod) ]
232 // [ dr_{strip} dphiStrip ]
233 // J = [ ]
234 // [ d d ]
235 // [----------(phiMod) ---------(phiMod)]
236 // [dr_{strip} dphiStrip ]
237 //
238 // Performing the derivative one gets:
239 //
240 // [B*O_x + C*O_y + rStrip rStrip*(B*O_y + O_x*sin(dPhi - phiStrip))]
241 // [---------------------- -----------------------------------------]
242 // [ ___ ___ ]
243 // [ \/ A \/ A ]
244 // J = [ ]
245 // [ -(B*O_y - C*O_x) rStrip*(B*O_x + C*O_y + rStrip) ]
246 // [ ----------------- ------------------------------- ]
247 // [ A A ]
248 //
249 // where
250 // 2 2 2
251 // A = O_x + 2*O_x*rStrip*cos(dPhi - phiStrip) + O_y - 2*O_y*rStrip*sin(dPhi - phiStrip) + rStrip
252 // B = cos(dPhi - phiStrip)
253 // C = -sin(dPhi - phiStrip)
254
255 double cosDPhiPhiStrip = std::cos(dphi - phi_strip);
256 double sinDPhiPhiStrip = std::sin(dphi - phi_strip);
257
258 double A = O_x*O_x + 2*O_x*r_strip*cosDPhiPhiStrip
259 + O_y*O_y - 2*O_y*r_strip*sinDPhiPhiStrip
260 + r_strip*r_strip;
261 double sqrtA = std::sqrt(A);
262
263
264 double B = cosDPhiPhiStrip;
265 double C = -sinDPhiPhiStrip;
266 Eigen::Matrix<double, 2, 2> jacobianStripPCToModulePC;
267 jacobianStripPCToModulePC(0, 0) = (B*O_x + C*O_y + r_strip)/sqrtA;
268 jacobianStripPCToModulePC(0, 1) = r_strip*(B*O_y + O_x*sinDPhiPhiStrip)/sqrtA;
269 jacobianStripPCToModulePC(1, 0) = -(B*O_y - C*O_x)/A;
270 jacobianStripPCToModulePC(1, 1) = r_strip*(B*O_x + C*O_y + r_strip)/A;
271
272 // covariance is given in STRIP PC
273 Matrix2D covStripPC = bchk.lCovariance;
274 // calculate covariance in MODULE PC using jacobian from above
275 Matrix2D covModulePC;
276 covModulePC = jacobianStripPCToModulePC * covStripPC * jacobianStripPCToModulePC.transpose();
277
278 // Mahalanobis distance uses inverse covariance as weights
279 Matrix2D weightStripPC = covStripPC.inverse();
280 Matrix2D weightModulePC = covModulePC.inverse();
281
282
283 double minDist = std::numeric_limits<double>::max();
284
285 Amg::Vector2D currentClosest;
286 double currentDist{0.0}; // initialise to zero
287
288 // do projection in STRIP PC
289
290 // first: STRIP system. locpo is in STRIP PC already
291 currentClosest = closestOnSegment(m_inLeftStripPC, m_outLeftStripPC, locpo_rotated, weightStripPC);
292 currentDist = squaredNorm(locpo_rotated-currentClosest, weightStripPC);
293 minDist = currentDist;
294
295 currentClosest = closestOnSegment(m_inRightStripPC, m_outRightStripPC, locpo_rotated, weightStripPC);
296 currentDist = squaredNorm(locpo_rotated-currentClosest, weightStripPC);
297 if(currentDist < minDist) {
298 minDist = currentDist;
299 }
300
301 // now: MODULE system. Need to transform locpo to MODULE PC
302 // transform is STRIP PC -> STRIP XY -> MODULE XY -> MODULE PC
303 Amg::Vector2D locpoStripXY(locpo_rotated[Trk::locR]*std::cos(locpo_rotated[Trk::locPhi]),
304 locpo_rotated[Trk::locR]*std::sin(locpo_rotated[Trk::locPhi]));
305 Amg::Vector2D locpoModulePC = stripXYToModulePC(locpoStripXY);
306
307
308 // now check edges in MODULE PC (inner and outer circle)
309 // assuming Mahalanobis distances are of same unit if covariance
310 // is correctly transformed
311 currentClosest = closestOnSegment(m_inLeftModulePC, m_inRightModulePC, locpoModulePC, weightModulePC);
312 currentDist = squaredNorm(locpoModulePC-currentClosest, weightModulePC);
313 if(currentDist < minDist) {
314 minDist = currentDist;
315 }
316
317 currentClosest = closestOnSegment(m_outLeftModulePC, m_outRightModulePC, locpoModulePC, weightModulePC);
318 currentDist = squaredNorm(locpoModulePC-currentClosest, weightModulePC);
319 if(currentDist < minDist) {
320 minDist = currentDist;
321 }
322
323 // compare resulting Mahalanobis distance to configured
324 // "number of sigmas"
325 // we square it b/c we never took the square root of the distance
326 return minDist < bchk.nSigmas*bchk.nSigmas;
327 }
328}
329
330bool
331Trk::AnnulusBoundsPC::insideLoc2(const Amg::Vector2D& locpo, double tol2) const
332{
333 // locpo is PC in STRIP SYSTEM
334 // need to perform internal rotation induced by m_phiAvg
335 Amg::Vector2D locpo_rotated = m_rotationStripPC * locpo;
336 double tolPhi = tol2;
337 double phiLoc = locpo_rotated[Trk::locPhi];
338
339 return phiLoc >= (m_phiMin - tolPhi) && phiLoc < (m_phiMax + tolPhi);
340}
341bool
342Trk::AnnulusBoundsPC::insideLoc1(const Amg::Vector2D& locpo, double tol1) const
343{
344 // locpo is PC in STRIP SYSTEM
345 // need to perform internal rotation induced by m_phiAvg
346 Amg::Vector2D locpo_rotated = m_rotationStripPC * locpo;
347 double tolR = tol1;
348 double phiLoc = locpo_rotated[Trk::locPhi];
349 double rLoc = locpo_rotated[Trk::locR];
350
351 // calculate R in MODULE SYSTEM to evaluate R-bounds
352 if (tolR == 0.) {
353 // don't need R, can use R^2
354 double r_mod2 = m_shiftPC[Trk::locR]*m_shiftPC[Trk::locR]
355 + rLoc*rLoc + 2.0*m_shiftPC[Trk::locR]*rLoc * std::cos(phiLoc - m_shiftPC[Trk::locPhi]);
356
357 if (r_mod2 < m_minR*m_minR || r_mod2 > m_maxR*m_maxR) {
358 return false;
359 }
360 }
361 else {
362 // use R
363 double r_mod = sqrt(m_shiftPC[Trk::locR]*m_shiftPC[Trk::locR]
364 + rLoc*rLoc + 2.0*m_shiftPC[Trk::locR]*rLoc * std::cos(phiLoc - m_shiftPC[Trk::locPhi]));
365
366 if (r_mod < (m_minR - tolR) || r_mod > (m_maxR + tolR)) {
367 return false;
368 }
369 }
370
371 return true;
372}
373
374double
376{
377 // find the closest point on all edges, calculate distance
378 // return smallest one
379 // closest distance is cartesian, we want the result in mm.
380
381 Amg::Vector2D locpo_rotated = m_rotationStripPC * locpo;
382
383 // locpo is given in STRIP PC, we need it in STRIP XY and possibly MODULE XY
384 double rStrip = locpo_rotated[Trk::locR];
385 double phiStrip = locpo_rotated[Trk::locPhi];
386 Amg::Vector2D locpoStripXY(rStrip*std::cos(phiStrip), rStrip*std::sin(phiStrip));
387 Amg::Vector2D locpoModuleXY = locpoStripXY + m_shiftXY;
388 double rMod = locpoModuleXY.norm();
389 double phiMod = locpoModuleXY.phi();
390
391 Amg::Vector2D closestStripPC;
392 double minDist = std::numeric_limits<double>::max();;
393 double curDist{0.0}; // initialise to 0
394
395 // for rmin
396 if (m_inRightModulePC[Trk::locPhi] <= phiMod && phiMod < m_inLeftModulePC[Trk::locPhi]) {
397 // is inside phi bounds, to comparison to rmin and r max
398 // r min
399 curDist = std::abs(m_minR - rMod);
400 minDist = std::min(minDist, curDist);
401 }
402 else {
403 // is outside phi bounds, closest can only be the edge points here
404
405 // in left
406 curDist = (m_inLeftStripXY - locpoStripXY).norm();
407 minDist = std::min(minDist, curDist);
408
409 // in right
410 curDist = (m_inRightStripXY - locpoStripXY).norm();
411 minDist = std::min(minDist, curDist);
412 }
413
414 if (m_phiMin <= phiStrip && phiStrip < m_phiMax) {
415 // r max
416 curDist = std::abs(m_maxR - rMod);
417 minDist = std::min(minDist, curDist);
418 }
419 else {
420 // out left
421 curDist = (m_outLeftStripXY - locpoStripXY).norm();
422 minDist = std::min(minDist, curDist);
423
424 // out right
425 curDist = (m_outRightStripXY - locpoStripXY).norm();
426 minDist = std::min(minDist, curDist);
427 }
428
429 Matrix2D weight = Matrix2D::Identity();
430
431 // phi left
432 Amg::Vector2D closestLeft = closestOnSegment(m_inLeftStripXY, m_outLeftStripXY, locpoStripXY, weight);
433 curDist = (closestLeft - locpoStripXY).norm();
434 if (curDist < minDist) {
435 minDist = curDist;
436 }
437
438 // phi right
439 Amg::Vector2D closestRight = closestOnSegment(m_inRightStripXY, m_outRightStripXY, locpoStripXY, weight);
440 curDist = (closestRight - locpoStripXY).norm();
441 if (curDist < minDist) {
442 minDist = curDist;
443 }
444
445 return minDist;
446}
447
448double
450{
451 return (rMax() + rMin()) * 0.5;
452}
453
454MsgStream& Trk::AnnulusBoundsPC::dump( MsgStream& sl ) const
455{
456 std::stringstream ss;
457 dump(ss);
458 sl << ss.str();
459 return sl;
460}
461
462std::ostream& Trk::AnnulusBoundsPC::dump( std::ostream& sl ) const
463{
464 sl << std::setiosflags(std::ios::fixed);
465 sl << std::setprecision(7);
466 sl << "Trk::AnnulusBoundsPC: (minR, maxR, phiMin, phiMax, phiAvg, origin(x, y)) = " << "(" ;
474 sl << ")";
475 sl << std::setprecision(-1);
476 return sl;
477}
478
479std::array<std::pair<double, double>,4 >
481 auto rot = m_rotationStripPC.inverse();
482
483 auto to_pair = [](const Amg::Vector2D& v) -> std::pair<double, double>
484 {
485 return {v[0], v[1]};
486 };
487
488 return {
489 to_pair(rot * m_outRightStripPC),
490 to_pair(rot * m_outLeftStripPC),
491 to_pair(rot * m_inLeftStripPC),
492 to_pair(rot * m_inRightStripPC)
493 };
494
495}
496
499{
500 Amg::Vector2D vecModuleXY = vStripXY + m_shiftXY;
501 return {vecModuleXY.norm(), vecModuleXY.phi()};
502}
503
506 const Amg::Vector2D& b,
507 const Amg::Vector2D& p,
508 const Eigen::Matrix<double, 2, 2>& weight)
509{
510 // connecting vector
511 auto n = b - a;
512 // squared norm of line
513 auto f = (n.transpose() * weight * n).value();
514 // weighted scalar product of line to point and segment line
515 auto u = ((p - a).transpose() * weight * n).value() / f;
516 // clamp to [0, 1], convert to point
517 return std::min(std::max(u, 0.0), 1.0) * n + a;
518}
519
520double
521Trk::AnnulusBoundsPC::squaredNorm(const Amg::Vector2D& v, const Eigen::Matrix<double, 2, 2>& weight)
522{
523 return (v.transpose() * weight * v).value();
524}
525
528{
529 return Eigen::Rotation2D<double>(m_phiAvg) * m_moduleOrigin;
530}
static Double_t a
static Double_t ss
double phiMax() const
Returns the left angular edge of the module.
static double squaredNorm(const Amg::Vector2D &v, const Eigen::Matrix< double, 2, 2 > &weight)
Eigen::Matrix< double, 2, 2 > Matrix2D
Amg::Vector2D m_outLeftModulePC
Amg::Vector2D stripXYToModulePC(const Amg::Vector2D &vStripXY) const
MsgStream & dump(MsgStream &sl) const override
helper which dumps the configuration into a stream.
Amg::Vector2D m_inRightStripPC
Transform2D m_rotationStripPC
Amg::Vector2D m_outRightStripPC
Eigen::Transform< double, 2, Eigen::Affine > Transform2D
bool inside(const Amg::Vector2D &locpo, double tol1=0., double tol2=0.) const override final
Returns if a point in local coordinates is inside the bounds.
Amg::Vector2D m_outLeftStripPC
double rMin() const
Returns inner radial bounds (module system)
Amg::Vector2D m_inRightModulePC
Amg::Vector2D m_inLeftStripPC
static std::pair< AnnulusBoundsPC, double > fromCartesian(const AnnulusBounds &annbo)
Static factory method to produce an instance of this class from the cartesian implementation.
double phiMin() const
Returns the right angular edge of the module.
Amg::Vector2D m_inRightStripXY
Amg::Vector2D m_outRightModulePC
Eigen::Rotation2D< double > Rotation2D
Amg::Vector2D m_inLeftModulePC
Amg::Vector2D m_inLeftStripXY
AnnulusBoundsPC(double minR, double maxR, double phiMin, double phiMax, Amg::Vector2D moduleOrigin={0, 0}, double phiAvg=0)
Default constructor from parameters.
std::vector< TDD_real_t > m_boundValues
Amg::Vector2D m_outRightStripXY
Amg::Vector2D moduleOrigin() const
Returns moduleOrigin, but rotated out, so avgPhi is already considered.
bool insideLoc2(const Amg::Vector2D &locpo, double tol2=0.) const override final
Check if local point is inside of phi bounds.
double r() const override
Returns middle radius.
std::array< std::pair< double, double >, 4 > corners() const
Returns the four corners of the bounds.
double rMax() const
Returns outer radial bounds (module system)
Amg::Vector2D m_moduleOrigin
double minDistance(const Amg::Vector2D &locpo) const override final
Return minimum distance a point is away from the bounds.
static Amg::Vector2D closestOnSegment(const Amg::Vector2D &a, const Amg::Vector2D &b, const Amg::Vector2D &p, const Eigen::Matrix< double, 2, 2 > &weight)
bool insideLoc1(const Amg::Vector2D &locpo, double tol1=0.) const override final
Check if local point is inside of r bounds.
Amg::Vector2D m_outLeftStripXY
Bounds for a annulus-like, planar Surface.
std::array< TDD_real_t, 4 > getEdgeLines() const
Returns the gradient and y-intercept of the left and right module edges.
const std::vector< TDD_real_t > & getBoundsValues() const
The BoundaryCheck class allows to steer the way surface boundaries are used for inside/outside checks...
int nSigmas
allowed sigmas for chi2 boundary check
BoundaryCheckType bcType
double toleranceLoc2
absolute tolerance in local 2 coordinate
bool checkLoc2
check local 2 coordinate
bool checkLoc1
check local 1 coordinate
@ absolute
absolute check including tolerances
double toleranceLoc1
absolute tolerance in local 1 coordinate
struct color C
Eigen::Matrix< double, 2, 1 > Vector2D
@ locY
local cartesian
Definition ParamDefs.h:38
@ locX
Definition ParamDefs.h:37
@ locR
Definition ParamDefs.h:44
@ v
Definition ParamDefs.h:78
@ u
Enums for curvilinear frames.
Definition ParamDefs.h:77
@ phi
Definition ParamDefs.h:75
@ locPhi
local polar
Definition ParamDefs.h:45
-event-from-file
hold the test vectors and ease the comparison