ATLAS Offline Software
Loading...
Searching...
No Matches
ConeSurface.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6// ConeSurface.cxx, (c) ATLAS Detector Software
8
9// Trk
12// Gaudi
13#include "GaudiKernel/MsgStream.h"
14//CxxUtils
16
17// default constructor
19 : Trk::Surface()
20 , m_bounds(nullptr)
21 , m_referencePoint(nullptr)
22 , m_rotSymmetryAxis(nullptr)
23{}
24
25// copy constructor
27 : Trk::Surface(csf)
28 , m_bounds(csf.m_bounds)
29 , m_referencePoint(nullptr)
30 , m_rotSymmetryAxis(nullptr)
31{}
32
33// copy constructor with shift
35 const Amg::Transform3D& transf)
36 : Trk::Surface(csf, transf)
37 , m_bounds(csf.m_bounds)
38 , m_referencePoint(nullptr)
39 , m_rotSymmetryAxis(nullptr)
40{}
41
42// constructor by opening angle and whether its symmetric or a single cone
44 double alpha,
45 bool symmetric)
46 : Trk::Surface(htrans)
47 , m_bounds(std::make_shared<const Trk::ConeBounds>(alpha, symmetric))
48 , m_referencePoint(nullptr)
49 , m_rotSymmetryAxis(nullptr)
50{}
51
52// constructor by opening angle and its z values
54 double alpha,
55 double zmin,
56 double zmax,
57 double halfPhi)
58 : Trk::Surface(htrans)
59 , m_bounds(std::make_shared<const Trk::ConeBounds>(alpha, zmin, zmax, halfPhi))
60 , m_referencePoint(nullptr)
61 , m_rotSymmetryAxis(nullptr)
62{}
63
64// constructor by ConeBounds
66 std::shared_ptr<const Trk::ConeBounds> cbounds)
67 : Trk::Surface(htrans)
68 , m_bounds(std::move(cbounds))
69 , m_referencePoint(nullptr)
70 , m_rotSymmetryAxis(nullptr)
71{
72}
73
74// constructor from transform, bounds not set.
76 : Trk::Surface(htrans)
77 , m_bounds(nullptr)
78 , m_referencePoint(nullptr)
79 , m_rotSymmetryAxis(nullptr)
80{}
81
82// Out-of-line dtor.
84
87{
88 if (this != &csf) {
90 m_bounds = csf.m_bounds;
91 m_referencePoint.store(nullptr);
92 m_rotSymmetryAxis.store(nullptr);
93 }
94 return *this;
95}
96
101 double l1, double l2, double phi, double theta, double qop,
102 std::optional<AmgSymMatrix(5)> cov) const {
103 return std::make_unique<ParametersT<5, Charged, ConeSurface>>(
104 l1, l2, phi, theta, qop, *this, std::move(cov));
105}
106
110 const Amg::Vector3D& position, const Amg::Vector3D& momentum, double charge,
111 std::optional<AmgSymMatrix(5)> cov) const {
112 return std::make_unique<ParametersT<5, Charged, ConeSurface>>(
113 position, momentum, charge, *this, std::move(cov));
114}
115
120 double l1, double l2, double phi, double theta, double qop,
121 std::optional<AmgSymMatrix(5)> cov) const {
122 return std::make_unique<ParametersT<5, Neutral, ConeSurface>>(
123 l1, l2, phi, theta, qop, *this, std::move(cov));
124}
125
130 const Amg::Vector3D& position, const Amg::Vector3D& momentum, double charge,
131 std::optional<AmgSymMatrix(5)> cov) const {
132 return std::make_unique<ParametersT<5, Neutral, ConeSurface>>(
133 position, momentum, charge, *this, std::move(cov));
134}
135
136// TODO: is the 0 always the cone center?
137const Amg::Vector3D&
139{
140 if (!m_referencePoint) {
141 // this is what was in cylinder
142 // double rMedium = bounds().r();
143 // double phi = bounds().averagePhi();
144 // Trk::GlobalPosition gp(rMedium*cos(phi), rMedium*sin(phi), 0.);
145 Amg::Vector3D gp(0., 0., 0.);
146 m_referencePoint.set(std::make_unique<Amg::Vector3D>(transform() * gp));
147 }
148 return (*m_referencePoint);
149}
150
151bool
153{
154 // first check the type not to compare apples with oranges
155 if (sf.type()!=Trk::SurfaceType::Cone){
156 return false;
157 }
158 return (*this) == static_cast<const Trk::ConeSurface&>(sf);
159}
160
161const Amg::Vector3D&
163{
164 if (!m_rotSymmetryAxis) {
165 Amg::Vector3D zAxis(transform().rotation().col(2));
166 m_rotSymmetryAxis.set(std::make_unique<Amg::Vector3D>(zAxis));
167 }
168 return (*m_rotSymmetryAxis);
169}
170
171// return the measurement frame: it's the tangential plane
174{
176 // construct the measurement frame
177 Amg::Vector3D measY(transform().rotation().col(2)); // measured Y is the z axis
178 Amg::Vector3D measDepth =
179 Amg::Vector3D(pos.x(), pos.y(), 0.).unit(); // measured z is the position transverse normalized
180 Amg::Vector3D measX(measY.cross(measDepth).unit()); // measured X is what comoes out of it
181 // the columnes
182 mFrame.col(0) = measX;
183 mFrame.col(1) = measY;
184 mFrame.col(2) = measDepth;
185 // return the rotation matrix
187 // return it
188 return mFrame;
189}
190// Avoid out-of-line-eigen calls
192void
194{
195 // create the position in the local 3d frame
196 double r = locpos[Trk::locZ] * bounds().tanAlpha();
197 double phi = locpos[Trk::locRPhi] / r;
198 Amg::Vector3D loc3Dframe(r * cos(phi), r * sin(phi), locpos[Trk::locZ]);
199 // transport it to the globalframe
200 glopos = transform() * loc3Dframe;
201}
202
203bool
205{
206 Amg::Vector3D loc3Dframe(inverseTransformMultHelper(glopos));
207 double r = loc3Dframe.z() * bounds().tanAlpha();
208 locpos = Amg::Vector2D(r * atan2(loc3Dframe.y(), loc3Dframe.x()), loc3Dframe.z());
209 // now decide on the quility of the transformation
210 // double inttol = r*0.0001;
211 // inttol = (inttol<0.01) ? 0.01 : 0.01; // ?
212 double inttol = 0.01;
213 return ((loc3Dframe.perp() - r) <= inttol);
214}
215
218 const Amg::Vector3D& dir,
219 bool forceDir,
220 Trk::BoundaryCheck bchk) const
221{
222 // transform to a frame with the cone along z, with the tip at 0
223 const Amg::Transform3D surfaceTrans = inverseTransformHelper();
224 Amg::Vector3D tpos1 = surfaceTrans * pos;
225 Amg::Vector3D tdir = surfaceTrans.linear() * dir;
226 // see the header for the formula derivation
227 double tan2Alpha = bounds().tanAlpha() * bounds().tanAlpha();
228 double A = tdir.x() * tdir.x() + tdir.y() * tdir.y() - tan2Alpha * tdir.z() * tdir.z();
229 double B = 2 * (tdir.x() * tpos1.x() + tdir.y() * tpos1.y() - tan2Alpha * dir.z() * tpos1.z());
230 double C = tpos1.x() * tpos1.x() + tpos1.y() * tpos1.y() - tan2Alpha * tpos1.z() * tpos1.z();
231 if (A == 0.)
232 A += 1e-16; // avoid div by zero
233
234 // use Andreas' quad solver, much more stable than what I wrote
235 Trk::RealQuadraticEquation solns(A, B, C);
236
237 Amg::Vector3D solution(0., 0., 0.);
238 double path = 0.;
239 bool isValid = false;
240 if (solns.solutions != Trk::none) {
241 double t1 = solns.first;
242 Amg::Vector3D soln1Loc(tpos1 + t1 * dir);
243 isValid = forceDir ? (t1 > 0.) : true;
244 // there's only one solution
245 if (solns.solutions == Trk::one) {
246 solution = soln1Loc;
247 path = t1;
248 } else {
249 double t2 = solns.second;
250 Amg::Vector3D soln2Loc(tpos1 + t2 * dir);
251 // both solutions have the same sign
252 if (t1 * t2 > 0. || !forceDir) {
253 if (t1 * t1 < t2 * t2) {
254 solution = soln1Loc;
255 path = t1;
256 } else {
257 solution = soln2Loc;
258 path = t2;
259 }
260 } else {
261 if (t1 > 0.) {
262 solution = soln1Loc;
263 path = t1;
264 } else {
265 solution = soln2Loc;
266 path = t2;
267 }
268 }
269 }
270 }
271 solution = transform() * solution;
272
273 isValid = bchk ? (isValid && isOnSurface(solution)) : isValid;
274 return Trk::Intersection(solution, path, isValid);
275}
276
278
279// TODO understand what is going on here (copied from cylinder,
280// because i really don't see what the idea is here vs. the other
281// straightLineDistanceEstimate, and this is harder to see whats
282// happening.
285{
286 return straightLineDistanceEstimate(pos, dir, false);
287}
288
291{
292 double tol = 0.001;
293
294 Amg::Vector3D Cntr = center(); // tip of the cone (i.e. join between halves)
295 Amg::Vector3D N = normal(); // this is the z-direction of the cone in
296 // global coordiantes i believe
297
298 Amg::Vector3D dPos = pos - Cntr; // pos w.r.t. cone tip
299 double posLength = sqrt(dPos.dot(dPos));
300 if (posLength < tol) // at origin of cone => on cone (avoid div by zero)
301 return {1, 0., true, 0.};
302 double posProj = dPos.dot(N);
303 double posProjAngle = acos(posProj / posLength);
304 double currDist = posLength * sin(posProjAngle - atan(bounds().tanAlpha()));
305 // solution on the surface
306 if (std::abs(currDist) < tol)
307 return {1, currDist, true, 0.};
308
309 // transform to a frame with the cone along z, with the tip a 0
310 Amg::Vector3D locFramePos = inverseTransformMultHelper(pos);
311 Amg::Vector3D locFrameDir = transform().rotation().inverse() * dir.normalized();
312
313 // solutions are in the form of a solution to a quadratic eqn.
314 double tan2Alpha = bounds().tanAlpha() * bounds().tanAlpha();
315 double A = locFrameDir.x() * locFrameDir.x() + locFrameDir.y() * locFrameDir.y() -
316 tan2Alpha * locFrameDir.z() * locFrameDir.z();
317 double B = 2 * (locFrameDir.x() * locFramePos.x() + locFrameDir.y() * locFramePos.y() -
318 tan2Alpha * locFrameDir.z() * locFramePos.z());
319 double C = locFramePos.x() * locFramePos.x() + locFramePos.y() * locFramePos.y() -
320 tan2Alpha * locFramePos.z() * locFramePos.z();
321 if (A == 0.)
322 A += 1e-16; // avoid div by zero
323 // use Andreas' quad solver, much more stable than what I wrote
324 Trk::RealQuadraticEquation solns(A, B, C);
325
326 double d2bound = 0.;
327 if (bound && solns.solutions != Trk::none) {
328 std::optional<Amg::Vector2D> p = std::nullopt;
329 if (std::abs(solns.first) < std::abs(solns.second)){
330 p = Surface::globalToLocal(locFramePos + solns.first * locFrameDir);
331 }
332 else{
333 p = Surface::globalToLocal(locFramePos + solns.second * locFrameDir);
334 }
335 if (p) {
336 d2bound = bounds().minDistance(*p);
337 }
338 if (d2bound < 0){
339 d2bound = 0;
340 }
341 }
342 double totDist = d2bound > 0. ? sqrt(d2bound * d2bound + currDist * currDist) : currDist;
343
344 switch (solns.solutions) {
345 case Trk::none:{
346 return {0, totDist, true, 0., 0.};
347 }
348 case Trk::one:{
349 return {1, totDist, true, solns.first};
350 }
351 case Trk::two:{
352 if (std::abs(solns.first) < std::abs(solns.second)){
353 return {2, totDist, true, solns.first, solns.second};
354 }
355 return {2, totDist, true, solns.second, solns.first};
356 }
357 default:{
358 return {0, totDist, true, 0., 0.};
359 }
360 };
361}
362
363double
365{
366 // (cos phi cos alpha, sin phi cos alpha, sgn z sin alpha)
367 bool applyTransform = !(transform().isApprox(Amg::Transform3D::Identity()));
368 Amg::Vector3D posLocal = applyTransform ? inverseTransformMultHelper(pos) : pos;
369 double phi = posLocal.phi();
370 double sgn = posLocal.z() > 0. ? -1. : +1.;
371 Amg::Vector3D normalC(cos(phi) * bounds().cosAlpha(), sin(phi) * bounds().cosAlpha(), sgn * bounds().sinAlpha());
372 if (applyTransform)
373 normalC = transform().linear() * normalC;
374 // back in global frame
375 double cAlpha = normalC.dot(mom.unit());
376 return (cAlpha != 0.) ? std::abs(1. / cAlpha) : 1.; // ST undefined for cAlpha=0
377}
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)
The BoundaryCheck class allows to steer the way surface boundaries are used for inside/outside checks...
Bounds for a conical Surface, the opening angle is stored in and always positively defined.
Definition ConeBounds.h:44
Class for a conical surface in the ATLAS detector.
Definition ConeSurface.h:51
CxxUtils::CachedUniquePtr< Amg::Vector3D > m_rotSymmetryAxis
virtual const ConeBounds & bounds() const override final
This method returns the ConeBounds by reference (NoBounds is not possible for cone)
virtual const Amg::Vector3D & rotSymmetryAxis() const
Return method for the rotational symmetry axis - the z-Axis of the HepTransform.
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 double pathCorrection(const Amg::Vector3D &, const Amg::Vector3D &) const override
the pathCorrection for derived classes with thickness
ConeSurface()
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...
virtual DistanceSolution straightLineDistanceEstimate(const Amg::Vector3D &pos, const Amg::Vector3D &dir) const override final
fast straight line distance to Surface
virtual void localToGlobal(const Amg::Vector2D &locp, const Amg::Vector3D &mom, Amg::Vector3D &glob) const override final
Specialized for ConeSurface : LocalToGlobal method without dynamic memory allocation.
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.
std::shared_ptr< const ConeBounds > m_bounds
The global reference point (== a point on thesurface)
virtual bool operator==(const Surface &sf) const override
Equality operator.
ConeSurface & operator=(const ConeSurface &csf)
Assignment operator.
virtual ~ConeSurface()
Destructor.
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 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 bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const override final
Specialized for ConeSurface : GlobalToLocal method without dynamic memory allocation - boolean checks...
CxxUtils::CachedUniquePtr< Amg::Vector3D > m_referencePoint
The rotational symmetry axis.
virtual Intersection straightLineIntersection(const Amg::Vector3D &pos, const Amg::Vector3D &dir, bool forceDir=false, BoundaryCheck bchk=false) const override final
fast straight line intersection schema - provides closest intersection and (signed) path length
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
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const =0
Specified by each surface type: GlobalToLocal method without dynamic memory allocation - boolean chec...
Amg::Vector3D inverseTransformMultHelper(const Amg::Vector3D &glopos) const
Surface()
Default Constructor for inheriting classes.
const Amg::Transform3D & transform() const
Returns HepGeom::Transform3D by reference.
virtual bool isOnSurface(const Amg::Vector3D &glopo, const BoundaryCheck &bchk=true, double tol1=0., double tol2=0.) const
This method returns true if the GlobalPosition is on the Surface for both, within or without check of...
Definition Surface.cxx:123
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.
@ locRPhi
Definition ParamDefs.h:40
@ theta
Definition ParamDefs.h:66
@ phi
Definition ParamDefs.h:75
@ locZ
local cylindrical
Definition ParamDefs.h:42
STL namespace.
hold the test vectors and ease the comparison