ATLAS Offline Software
Loading...
Searching...
No Matches
CylinderSurface.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
4
6// CylinderSurface.cxx, (c) ATLAS Detector Software
8
9// Trk
12// Gaudi
13#include "GaudiKernel/MsgStream.h"
14//CxxUtils
16// STD
17#include <iomanip>
18#include <iostream>
19
20// default constructor
22 : Trk::Surface()
23 , m_bounds(nullptr)
24 , m_referencePoint(nullptr)
25 , m_rotSymmetryAxis(nullptr)
26{}
27
28// copy constructor
35
36// copy constructor with shift
38 const Amg::Transform3D& transf)
39 : Trk::Surface(csf, transf)
40 , m_bounds(csf.m_bounds)
41 , m_referencePoint(nullptr)
42 , m_rotSymmetryAxis(nullptr)
43{}
44
45// constructor by radius and halflenght
47 double radius,
48 double hlength)
49 : Trk::Surface(htrans)
50 , m_bounds(std::make_shared<const Trk::CylinderBounds>(radius, hlength))
51 , m_referencePoint(nullptr)
52 , m_rotSymmetryAxis(nullptr)
53{}
54
55// constructor by radius, halflenght and phisector
57 double radius,
58 double hphi,
59 double hlength)
60 : Trk::Surface(htrans)
61 , m_bounds(std::make_shared<Trk::CylinderBounds>(radius, hphi, hlength))
62 , m_referencePoint(nullptr)
63 , m_rotSymmetryAxis(nullptr)
64{}
65
66// constructor by CylinderBounds
68 std::shared_ptr<const Trk::CylinderBounds> cbounds)
69 : Trk::Surface(htrans)
70 , m_bounds(std::move(cbounds))
71 , m_referencePoint(nullptr)
72 , m_rotSymmetryAxis(nullptr)
73{
74}
75
76// constructor from transform
78 : Trk::Surface(htrans)
79 , m_bounds(nullptr)
80 , m_referencePoint(nullptr)
81 , m_rotSymmetryAxis(nullptr)
82{}
83
84// constructor by radius and halflength
85Trk::CylinderSurface::CylinderSurface(double radius, double hlength)
86 : Trk::Surface()
87 , m_bounds(std::make_shared<Trk::CylinderBounds>(radius, hlength))
88 , m_referencePoint(nullptr)
89 , m_rotSymmetryAxis(nullptr)
90{}
91
92// constructor by radius, halflength and phisector
94 double hphi,
95 double hlength)
96 : Trk::Surface()
97 , m_bounds(std::make_shared<Trk::CylinderBounds>(radius, hphi, hlength))
98 , m_referencePoint(nullptr)
99 , m_rotSymmetryAxis(nullptr)
100{}
101
102// constructor by CylinderBounds
103Trk::CylinderSurface::CylinderSurface(std::shared_ptr<const Trk::CylinderBounds> cbounds)
104 : Trk::Surface()
105 , m_bounds(std::move(cbounds))
106 , m_referencePoint(nullptr)
107 , m_rotSymmetryAxis(nullptr)
108{
109}
110
113{
114 if (this != &csf) {
116 m_bounds = csf.m_bounds;
117 m_referencePoint.store(nullptr);
118 m_rotSymmetryAxis.store(nullptr);
119 }
120 return *this;
121}
122
127 double l1, double l2, double phi, double theta, double qop,
128 std::optional<AmgSymMatrix(5)> cov) const {
129 return std::make_unique<ParametersT<5, Charged, CylinderSurface>>(
130 l1, l2, phi, theta, qop, *this, std::move(cov));
131}
132
137 const Amg::Vector3D& position, const Amg::Vector3D& momentum, double charge,
138 std::optional<AmgSymMatrix(5)> cov) const {
139 return std::make_unique<ParametersT<5, Charged, CylinderSurface>>(
140 position, momentum, charge, *this, std::move(cov));
141}
142
147 double l1, double l2, double phi, double theta, double qop,
148 std::optional<AmgSymMatrix(5)> cov) const {
149 return std::make_unique<ParametersT<5, Neutral, CylinderSurface>>(
150 l1, l2, phi, theta, qop, *this, std::move(cov));
151}
152
157 const Amg::Vector3D& position, const Amg::Vector3D& momentum, double charge,
158 std::optional<AmgSymMatrix(5)> cov) const {
159 return std::make_unique<ParametersT<5, Neutral, CylinderSurface>>(
160 position, momentum, charge, *this, std::move(cov));
161}
162
163const Amg::Vector3D&
165{
166 if (!m_referencePoint) {
167 double rMedium = bounds().r();
168 double phi = bounds().averagePhi();
169 Amg::Vector3D gp(rMedium * cos(phi), rMedium * sin(phi), 0.);
170 m_referencePoint.set(std::make_unique<Amg::Vector3D>(transform() * gp));
171 }
172 return (*m_referencePoint);
173}
174
175bool
177{
178 // first check the type not to compare apples with oranges
179 if (sf.type()!=Trk::SurfaceType::Cylinder){
180 return false;
181 }
182 return (*this) == static_cast<const Trk::CylinderSurface&>(sf);
183}
184
185// return the measurement frame: it's the tangential plane
188 const Amg::Vector3D&) const
189{
191 // construct the measurement frame
192 Amg::Vector3D measY(
193 transform().rotation().col(2)); // measured Y is the z axis
194 Amg::Vector3D measDepth =
195 Amg::Vector3D(pos.x(), pos.y(), 0.)
196 .unit(); // measured z is the position transverse normalized
197 Amg::Vector3D measX(
198 measY.cross(measDepth).unit()); // measured X is what comoes out of it
199 // the columnes
200 mFrame.col(0) = measX;
201 mFrame.col(1) = measY;
202 mFrame.col(2) = measDepth;
203 // return the rotation matrix
204 return mFrame;
205}
206
207const Amg::Vector3D&
209{
210 if (!m_rotSymmetryAxis) {
211 Amg::Vector3D zAxis(transform().rotation().col(2));
212 m_rotSymmetryAxis.set(std::make_unique<Amg::Vector3D>(zAxis));
213 }
214 return (*m_rotSymmetryAxis);
215}
216
217// Avoid out-of-line-eigen calls
219void
221 const Amg::Vector3D&,
222 Amg::Vector3D& glopos) const
223{
224 // create the position in the local 3d frame
225 double r = bounds().r();
226 double phi = locpos[Trk::locRPhi] / r;
227 glopos = Amg::Vector3D(r * cos(phi), r * sin(phi), locpos[Trk::locZ]);
228 // transform it to the globalframe: CylinderSurfaces are allowed to have 0
229 // pointer transform
231 glopos = transform() * glopos;
232}
233
234bool
236 const Amg::Vector3D&,
237 Amg::Vector2D& locpos) const
238{
239 // get the transform & transform global position into cylinder frame
240 // transform it to the globalframe: CylinderSurfaces are allowed to have 0
241 // pointer transform
242 double radius = 0.;
243 double inttol = bounds().r() * 0.0001;
244 if (inttol < 0.01)
245 inttol = 0.01;
246 // do the transformation or not
248 Amg::Vector3D loc3Dframe(inverseTransformMultHelper(glopos));
249 locpos = Amg::Vector2D(bounds().r() * loc3Dframe.phi(), loc3Dframe.z());
250 radius = loc3Dframe.perp();
251 } else {
252 locpos = Amg::Vector2D(bounds().r() * glopos.phi(), glopos.z());
253 radius = glopos.perp();
254 }
255 // return true or false
256 return (fabs(radius - bounds().r()) <= inttol);
257}
258
259bool
261 const Trk::BoundaryCheck& bchk,
262 double tol1,
263 double tol2) const
264{
265 Amg::Vector3D loc3Dframe =
267 return (bchk ? bounds().inside3D(loc3Dframe,
270 : true);
271}
272
275 const Amg::Vector3D& dir,
276 bool forceDir,
277 Trk::BoundaryCheck bchk) const
278{
279 bool needsTransform = m_transforms || m_associatedDetElement;
280 // create the hep points
281 Amg::Vector3D point1 = pos;
282 Amg::Vector3D direction = dir;
283 if (needsTransform) {
285 point1 = invTrans * pos;
286 direction = invTrans.linear() * dir;
287 }
288 // the bounds radius
289 double R = bounds().r();
290 double t1 = 0.;
291 double t2 = 0.;
292 if (direction.x()) {
293 // get line and circle constants
294 double idirx = 1. / direction.x();
295 double k = direction.y() * idirx;
296 double d = point1.y() - point1.x() * k;
297 // and solve the qaudratic equation
298 Trk::RealQuadraticEquation pquad(1 + k * k, 2 * k * d, d * d - R * R);
299 if (pquad.solutions != Trk::none) {
300 // the solutions in the 3D frame of the cylinder
301 t1 = (pquad.first - point1.x()) * idirx;
302 t2 = (pquad.second - point1.x()) * idirx;
303 } else // bail out if no solution exists
304 return {pos, 0., false};
305 } else if (direction.y()) {
306 // x value is the one of point1
307 // x^2 + y^2 = R^2
308 // y = sqrt(R^2-x^2)
309 double x = point1.x();
310 double r2mx2 = R * R - x * x;
311 // bail out if no solution
312 if (r2mx2 < 0.)
313 return {pos, 0., false};
314 double y = sqrt(r2mx2);
315 // assign parameters and solutions
316 double idiry = 1. / direction.y();
317 t1 = (y - point1.y()) * idiry;
318 t2 = (-y - point1.y()) * idiry;
319 } else {
320 return {pos, 0., false};
321 }
322 Amg::Vector3D sol1raw(point1 + t1 * direction);
323 Amg::Vector3D sol2raw(point1 + t2 * direction);
324 // now reorder and return
325 Amg::Vector3D solution(0, 0, 0);
326 double path = 0.;
327
328 // first check the validity of the direction
329 bool isValid = true;
330
331 // both solutions are of same sign, take the smaller, but flag as false if not
332 // forward
333 if (t1 * t2 > 0 || !forceDir) {
334 // asign validity
335 isValid = forceDir ? (t1 > 0.) : true;
336 // assign the right solution
337 if (t1 * t1 < t2 * t2) {
338 solution = sol1raw;
339 path = t1;
340 } else {
341 solution = sol2raw;
342 path = t2;
343 }
344 } else {
345 if (t1 > 0.) {
346 solution = sol1raw;
347 path = t1;
348 } else {
349 solution = sol2raw;
350 path = t2;
351 }
352 }
353 // the solution is still in the local 3D frame, direct check
354 isValid =
355 bchk ? (isValid && m_bounds->inside3D(solution,
358 : isValid;
359
360 // now return
361 return needsTransform ? Intersection(transform() * solution, path, isValid)
362 : Intersection(solution, path, isValid);
363}
364
366
367// We compile this function with optimization, even in debug builds; otherwise,
368// the heavy use of Eigen makes it too slow. However, from here we may call
369// to out-of-line Eigen code that is linked from other DSOs; in that case,
370// it would not be optimized. Avoid this by forcing all Eigen code
371// to be inlined here if possible.
375 const Amg::Vector3D& pos,
376 const Amg::Vector3D& dir) const
377{
378 double tol = 0.001;
379
380 const Amg::Vector3D& X = center(); // point
381 const Amg::Vector3D& S = normal(); // vector
382
383 double radius = bounds().r();
384 double sp = pos.dot(S);
385 double sc = X.dot(S);
386 double dp = dir.dot(S);
387 Amg::Vector3D dx = X - pos - (sc - sp) * S; // vector
388 Amg::Vector3D ax = dir - dp * S; // vector
389
390 double A = ax.dot(ax); // size of projected direction (squared)
391 double B = ax.dot(dx); // dot product (->cos angle)
392 double C = dx.dot(dx); // distance to axis (squared)
393 double currDist = radius - sqrt(C);
394
395 if (A == 0.) { // direction parallel to cylinder axis
396 if (fabs(currDist) < tol) {
397 return {1, 0., true, 0.}; // solution at surface
398 }
399 return {
400 0, currDist, true, 0.}; // point of closest approach without intersection
401 }
402
403 // minimal distance to cylinder axis
404 // The [[maybe_unused]] declaration is to suppress redundant division checking
405 // here. Even a tiny change in rmin (~1e-13) can cause huge changes in the
406 // reconstructed output, so don't change how it's evaluated.
407 [[maybe_unused]] const double rmin_tmp = B * B / A;
408 const double rmin2 = C - rmin_tmp;
409 const double rmin = rmin2 < 0 ? 0 : sqrt(rmin2);
410
411 if (rmin > radius) { // no intersection
412 double first = B / A;
413 return {
414 0,
415 currDist,
416 true,
417 first}; // point of closest approach without intersection
418 }
419 if (fabs(rmin - radius) <
420 tol) { // tangential 'intersection' - return double solution
421 double first = B / A;
422 return {2, currDist, true, first, first};
423 }
424 // The [[maybe_unused]] declaration here suppresses redundant division
425 // checking. We don't want to rewrite how this is evaluated due to
426 // instabilities.
427 [[maybe_unused]] const double b_a = B / A;
428 const double x = sqrt((radius - rmin) * (radius + rmin) / A);
429 double first = b_a - x;
430 double second = b_a + x;
431 if (first >= 0.) {
432 return {2, currDist, true, first, second};
433 }
434 if (second <= 0.) {
435 return {2, currDist, true, second, first};
436 } // inside cylinder
437 return {2, currDist, true, second, first};
438}
439
442 const Amg::Vector3D& dir,
443 bool bound) const
444{
445 const double tolb = .01;
446
447 const Amg::Transform3D& T = transform();
448 // double Ax[3] = {T.xx(),T.yx(),T.zx()};
449 // double Ay[3] = {T.xy(),T.yy(),T.zy()};
450 // double Az[3] = {T.xz(),T.yz(),T.zz()};
451
452 // Transformation to cylinder system coordinates
453 //
454
455 // BEGIN here is what i guess this might mean: BEGIN
456 Amg::Vector3D Ax = T.rotation().col(0);
457 Amg::Vector3D Ay = T.rotation().col(1);
458 Amg::Vector3D Az = T.rotation().col(2);
459
460 Amg::Vector3D dxyz = pos - T.translation();
461 double x = dxyz.dot(Ax);
462 double y = dxyz.dot(Ay);
463 double z = dxyz.dot(Az);
464 double ax = dir.dot(Ax);
465 double ay = dir.dot(Ay);
466 double at = ax * ax + ay * ay;
467 double r = sqrt(x * x + y * y);
468 double R = bounds().r();
469
470 // END here is what i guessed this means END
471
472 // double dx = pos[0]-T.dx() ;
473 // double dy = pos[1]-T.dy() ;
474 // double dz = pos[2]-T.dz() ;
475 // double x = dx*Ax[0]+dy*Ax[1]+dz*Ax[2] ;
476 // double y = dx*Ay[0]+dy*Ay[1]+dz*Ay[2] ;
477 // double z = dx*Az[0]+dy*Az[1]+dz*Az[2] ;
478 // double ax = dir[0]*Ax[0]+dir[1]*Ax[1]+dir[2]*Ax[2];
479 // double ay = dir[0]*Ay[0]+dir[1]*Ay[1]+dir[2]*Ay[2];
480 // double at = ax*ax+ay*ay ;
481 // double r = sqrt(x*x+y*y) ;
482 // double R = bounds().r() ;
483
484 // Step to surface
485 //
486 int ns = 0;
487 double s1 = 0.;
488 double s2 = 0.;
489
490 if (at != 0.) {
491
492 const double inv_at = 1. / at;
493 double A = -(ax * x + ay * y) * inv_at;
494 double B = A * A + (R - r) * (R - r) * inv_at;
495
496 if (B >= 0.) {
497
498 B = sqrt(B);
499 if (B > tolb) {
500 if (A > 0.) {
501 s1 = A - B;
502 s2 = A + B;
503 } else {
504 s1 = A + B;
505 s2 = A - B;
506 }
507 ns = 2;
508 } else {
509 s1 = A;
510 ns = 1;
511 }
512 }
513 }
514 double sr = r - R;
515 if (!bound)
516 return {ns, fabs(sr), true, s1, s2};
517
518 // Min distance to surface
519 //
520 Amg::Vector2D lp(atan2(y, x) * R, 0.);
521
522 double d = bounds().minDistance(lp);
523 double sz = fabs(z) - bounds().halflengthZ();
524 if (sz <= 0.)
525 sz = 0.;
526 double dist = sr * sr + sz * sz;
527 if (d > 0.)
528 dist += ((d * d) * (sr / R + 1.));
529
530 return {ns, sqrt(dist), true, s1, s2};
531}
double charge(const T &p)
Definition AtlasPID.h:997
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition AtlasPID.h:878
#define AmgSymMatrix(dim)
static Double_t sp
static Double_t sz
static Double_t sc
The BoundaryCheck class allows to steer the way surface boundaries are used for inside/outside checks...
Bounds for a cylindrical Surface.
Class for a CylinderSurface in the ATLAS detector.
virtual NeutralTrackParametersUniquePtr createUniqueNeutralParameters(double l1, double l2, double phi, double theta, double qop, std::optional< AmgSymMatrix(5)> cov=std::nullopt) const override final
Use the Surface as a ParametersBase constructor, from local parameters - neutral.
virtual void localToGlobal(const Amg::Vector2D &locp, const Amg::Vector3D &mom, Amg::Vector3D &glob) const override
Specialized for CylinderSurface : LocalToGlobal method without dynamic memory allocation.
CylinderSurface()
Default Constructor.
virtual Amg::Vector3D normal(const Amg::Vector2D &locpo) const override final
Return method for surface normal information at a given local point, overwrites the normal() from bas...
std::shared_ptr< const CylinderBounds > m_bounds
The global reference point (== a point on the surface)
virtual const Amg::Vector3D & rotSymmetryAxis() const
Return method for the rotational symmetry axis - the z-Axis of the HepTransform.
CxxUtils::CachedUniquePtr< Amg::Vector3D > m_rotSymmetryAxis
CylinderSurface & operator=(const CylinderSurface &csf)
Assignment operator.
virtual Intersection straightLineIntersection(const Amg::Vector3D &pos, const Amg::Vector3D &dir, bool forceDir=false, Trk::BoundaryCheck bchk=false) const override final
fast straight line intersection schema - provides closest intersection and (signed) path length
virtual const Amg::Vector3D & globalReferencePoint() const override final
Returns a global reference point: For the Cylinder this is Where denotes the averagePhi() of the cy...
virtual bool isOnSurface(const Amg::Vector3D &glopo, const BoundaryCheck &bchk=true, double tol1=0., double tol2=0.) const override
This method returns true if the GlobalPosition is on the Surface for both, within or without check of...
virtual Amg::RotationMatrix3D measurementFrame(const Amg::Vector3D &glopos, const Amg::Vector3D &glomom) const override final
Return the measurement frame - this is needed for alignment, in particular for StraightLine and Perig...
virtual DistanceSolution straightLineDistanceEstimate(const Amg::Vector3D &pos, const Amg::Vector3D &dir) const override
fast distance to Surface
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const override
Specialized for CylinderSurface : GlobalToLocal method without dynamic memory allocation - boolean ch...
virtual const CylinderBounds & bounds() const override final
This method returns the CylinderBounds by reference (NoBounds is not possible for cylinder)
CxxUtils::CachedUniquePtr< Amg::Vector3D > m_referencePoint
The rotational symmetry axis.
virtual bool operator==(const Surface &sf) const override
Equality operator.
virtual Surface::ChargedTrackParametersUniquePtr createUniqueTrackParameters(double l1, double l2, double phi, double theta, double qop, std::optional< AmgSymMatrix(5)> cov=std::nullopt) const override final
Use the Surface as a ParametersBase constructor, from local parameters - charged.
Access to distance solutions.
Abstract Base Class for tracking surfaces.
Amg::Transform3D inverseTransformHelper() const
Helper method to factorize in one place common operations calculate inverse transofrm and multiply wi...
std::unique_ptr< ParametersBase< 5, Trk::Charged > > ChargedTrackParametersUniquePtr
Unique ptr types.
Surface & operator=(const Surface &sf)
Definition Surface.cxx:91
static constexpr double s_onSurfaceTolerance
Tolerance for being on Surface.
const TrkDetElementBase * m_associatedDetElement
Not owning Pointer to the Detector Element.
Amg::Vector3D inverseTransformMultHelper(const Amg::Vector3D &glopos) const
Surface()
Default Constructor for inheriting classes.
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
std::unique_ptr< Transforms > m_transforms
Unique Pointer to the Transforms struct.
const Amg::Vector3D & center() const
Returns the center position of the Surface.
std::unique_ptr< ParametersBase< 5, Trk::Neutral > > NeutralTrackParametersUniquePtr
int r
Definition globals.cxx:22
#define ATH_FLATTEN
struct color C
Eigen::Matrix< double, 3, 3 > RotationMatrix3D
Eigen::Affine3d Transform3D
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
Ensure that the ATLAS eigen extensions are properly loaded.
@ x
Definition ParamDefs.h:55
@ z
global position (cartesian)
Definition ParamDefs.h:57
@ locRPhi
Definition ParamDefs.h:40
@ theta
Definition ParamDefs.h:66
@ y
Definition ParamDefs.h:56
@ phi
Definition ParamDefs.h:75
@ locZ
local cylindrical
Definition ParamDefs.h:42
STL namespace.
hold the test vectors and ease the comparison