Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CylinderSurface.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file CylinderSurface.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2016-2020 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
18 
19 #include <algorithm>
20 #include <cassert>
21 #include <cmath>
22 #include <utility>
23 #include <vector>
24 
25 namespace Acts {
26 class DetectorElementBase;
27 } // namespace Acts
28 
31 
33  : GeometryObject(), Surface(other), m_bounds(other.m_bounds) {}
34 
36  const CylinderSurface& other,
37  const Transform3& shift)
38  : GeometryObject(), Surface(gctx, other, shift), m_bounds(other.m_bounds) {}
39 
41  double radius, double halfz,
42  double halfphi, double avphi,
43  double bevelMinZ, double bevelMaxZ)
44  : Surface(transform),
45  m_bounds(std::make_shared<const CylinderBounds>(
46  radius, halfz, halfphi, avphi, bevelMinZ, bevelMaxZ)) {}
47 
49  std::shared_ptr<const CylinderBounds> cbounds,
50  const DetectorElementBase& detelement)
51  : Surface(detelement), m_bounds(std::move(cbounds)) {
53  throw_assert(m_bounds, "CylinderBounds must not be nullptr");
54 }
55 
57  const Transform3& transform, std::shared_ptr<const CylinderBounds> cbounds)
58  : Surface(transform), m_bounds(std::move(cbounds)) {
59  throw_assert(m_bounds, "CylinderBounds must not be nullptr");
60 }
61 
63  const CylinderSurface& other) {
64  if (this != &other) {
65  Surface::operator=(other);
66  m_bounds = other.m_bounds;
67  }
68  return *this;
69 }
70 
71 // return the binning position for ordering in the BinnedArray
73  const GeometryContext& gctx, BinningValue bValue) const {
74  // special binning type for R-type methods
75  if (bValue == Acts::binR || bValue == Acts::binRPhi) {
76  double R = bounds().get(CylinderBounds::eR);
77  double phi = bounds().get(CylinderBounds::eAveragePhi);
78  return localToGlobal(gctx, Vector2{phi * R, 0}, Vector3{});
79  }
80  // give the center as default for all of these binning types
81  // binX, binY, binZ, binR, binPhi, binRPhi, binH, binEta
82  return center(gctx);
83 }
84 
85 // return the measurement frame: it's the tangential plane
87  const GeometryContext& gctx, const Vector3& position,
88  const Vector3& /*direction*/) const {
89  RotationMatrix3 mFrame;
90  // construct the measurement frame
91  // measured Y is the z axis
92  Vector3 measY = rotSymmetryAxis(gctx);
93  // measured z is the position normalized transverse (in local)
94  Vector3 measDepth = normal(gctx, position);
95  // measured X is what comoes out of it
96  Vector3 measX(measY.cross(measDepth).normalized());
97  // assign the columnes
98  mFrame.col(0) = measX;
99  mFrame.col(1) = measY;
100  mFrame.col(2) = measDepth;
101  // return the rotation matrix
102  return mFrame;
103 }
104 
106  return Surface::Cylinder;
107 }
108 
110  const GeometryContext& gctx, const Vector2& lposition,
111  const Vector3& /*direction*/) const {
112  // create the position in the local 3d frame
113  double r = bounds().get(CylinderBounds::eR);
114  double phi = lposition[Acts::eBoundLoc0] / r;
115  Vector3 position(r * cos(phi), r * sin(phi), lposition[Acts::eBoundLoc1]);
116  return transform(gctx) * position;
117 }
118 
120  const GeometryContext& gctx, const Vector3& position,
121  const Vector3& /*direction*/, double tolerance) const {
122  double inttol = tolerance;
123  if (tolerance == s_onSurfaceTolerance) {
124  // transform default value!
125  // @TODO: check if s_onSurfaceTolerance would do here
126  inttol = bounds().get(CylinderBounds::eR) * 0.0001;
127  }
128  if (inttol < 0.01) {
129  inttol = 0.01;
130  }
131  const Transform3& sfTransform = transform(gctx);
132  Transform3 inverseTrans(sfTransform.inverse());
133  Vector3 loc3Dframe(inverseTrans * position);
134  if (std::abs(perp(loc3Dframe) - bounds().get(CylinderBounds::eR)) > inttol) {
135  return Result<Vector2>::failure(SurfaceError::GlobalPositionNotOnSurface);
136  }
138  {bounds().get(CylinderBounds::eR) * phi(loc3Dframe), loc3Dframe.z()});
139 }
140 
142  return "Acts::CylinderSurface";
143 }
144 
146  const GeometryContext& gctx, const Acts::Vector2& lposition) const {
147  double phi = lposition[Acts::eBoundLoc0] / m_bounds->get(CylinderBounds::eR);
148  Vector3 localNormal(cos(phi), sin(phi), 0.);
149  return Vector3(transform(gctx).matrix().block<3, 3>(0, 0) * localNormal);
150 }
151 
153  const GeometryContext& gctx, const Acts::Vector3& position) const {
154  const Transform3& sfTransform = transform(gctx);
155  // get it into the cylinder frame
156  Vector3 pos3D = sfTransform.inverse() * position;
157  // set the z coordinate to 0
158  pos3D.z() = 0.;
159  // normalize and rotate back into global if needed
160  return sfTransform.linear() * pos3D.normalized();
161 }
162 
165  const Acts::Vector3& direction) const {
166  Vector3 normalT = normal(gctx, position);
167  double cosAlpha = normalT.dot(direction);
168  return std::fabs(1. / cosAlpha);
169 }
170 
172  return (*m_bounds.get());
173 }
174 
176  const GeometryContext& gctx, size_t lseg) const {
177  auto ctrans = transform(gctx);
178 
179  // Prepare vertices and faces
180  std::vector<Vector3> vertices = bounds().createCircles(ctrans, lseg);
181  std::vector<Polyhedron::FaceType> faces;
182  std::vector<Polyhedron::FaceType> triangularMesh;
183 
184  bool fullCylinder = bounds().coversFullAzimuth();
185 
186  auto facesMesh =
187  detail::FacesHelper::cylindricalFaceMesh(vertices, fullCylinder);
188  return Polyhedron(vertices, facesMesh.first, facesMesh.second, false);
189 }
190 
192  const GeometryContext& gctx) const {
193  // fast access via transform matrix (and not rotation())
194  return transform(gctx).matrix().block<3, 1>(0, 2);
195 }
196 
198  const Transform3& transform, const Vector3& position,
199  const Vector3& direction) const {
200  // Solve for radius R
201  double R = bounds().get(CylinderBounds::eR);
202 
203  // Get the transformation matrtix
204  const auto& tMatrix = transform.matrix();
205  Vector3 caxis = tMatrix.block<3, 1>(0, 2).transpose();
206  Vector3 ccenter = tMatrix.block<3, 1>(0, 3).transpose();
207 
208  // Check documentation for explanation
209  Vector3 pc = position - ccenter;
210  Vector3 pcXcd = pc.cross(caxis);
211  Vector3 ldXcd = direction.cross(caxis);
212  double a = ldXcd.dot(ldXcd);
213  double b = 2. * (ldXcd.dot(pcXcd));
214  double c = pcXcd.dot(pcXcd) - (R * R);
215  // And solve the qaudratic equation
216  return detail::RealQuadraticEquation(a, b, c);
217 }
218 
220  const GeometryContext& gctx, const Vector3& position,
221  const Vector3& direction, const BoundaryCheck& bcheck,
222  ActsScalar tolerance) const {
223  const auto& gctxTransform = transform(gctx);
224 
225  // Solve the quadratic equation
226  auto qe = intersectionSolver(gctxTransform, position, direction);
227 
228  // If no valid solution return a non-valid surfaceIntersection
229  if (qe.solutions == 0) {
230  return {{Intersection3D::invalid(), Intersection3D::invalid()}, this};
231  }
232 
233  // Check the validity of the first solution
234  Vector3 solution1 = position + qe.first * direction;
235  Intersection3D::Status status1 = std::abs(qe.first) < std::abs(tolerance)
236  ? Intersection3D::Status::onSurface
237  : Intersection3D::Status::reachable;
238 
239  // Helper method for boundary check
240  auto boundaryCheck =
241  [&](const Vector3& solution,
243  // No check to be done, return current status
244  if (!bcheck) {
245  return status;
246  }
247  const auto& cBounds = bounds();
248  if (cBounds.coversFullAzimuth() and
249  bcheck.type() == BoundaryCheck::Type::eAbsolute) {
250  // Project out the current Z value via local z axis
251  // Built-in local to global for speed reasons
252  const auto& tMatrix = gctxTransform.matrix();
253  // Create the reference vector in local
254  const Vector3 vecLocal(solution - tMatrix.block<3, 1>(0, 3));
255  double cZ = vecLocal.dot(tMatrix.block<3, 1>(0, 2));
256  double modifiedTolerance = tolerance + bcheck.tolerance()[eBoundLoc1];
257  double hZ = cBounds.get(CylinderBounds::eHalfLengthZ) + modifiedTolerance;
258  return std::abs(cZ) < std::abs(hZ) ? status
259  : Intersection3D::Status::missed;
260  }
261  return (isOnSurface(gctx, solution, direction, bcheck)
262  ? status
263  : Intersection3D::Status::missed);
264  };
265  // Check first solution for boundary compatibility
266  status1 = boundaryCheck(solution1, status1);
267  // Set the intersection
268  Intersection3D first(solution1, qe.first, status1);
269  if (qe.solutions == 1) {
270  return {{first, first}, this};
271  }
272  // Check the validity of the second solution
273  Vector3 solution2 = position + qe.second * direction;
274  Intersection3D::Status status2 = std::abs(qe.second) < std::abs(tolerance)
275  ? Intersection3D::Status::onSurface
276  : Intersection3D::Status::reachable;
277  // Check first solution for boundary compatibility
278  status2 = boundaryCheck(solution2, status2);
279  Intersection3D second(solution2, qe.second, status2);
280  // Order based on path length
281  if (first.pathLength() <= second.pathLength()) {
282  return {{first, second}, this};
283  }
284  return {{second, first}, this};
285 }
286 
288  const GeometryContext& gctx, const FreeVector& parameters) const {
289  // The global position
290  const auto position = parameters.segment<3>(eFreePos0);
291  // The direction
292  const auto direction = parameters.segment<3>(eFreeDir0);
293  // The vector between position and center
294  const auto pcRowVec = (position - center(gctx)).transpose().eval();
295  // The rotation
296  const auto& rotation = transform(gctx).rotation();
297  // The local frame x/y/z axis
298  const auto& localXAxis = rotation.col(0);
299  const auto& localYAxis = rotation.col(1);
300  const auto& localZAxis = rotation.col(2);
301  // The local coordinates
302  const auto localPos = (rotation.transpose() * position).eval();
303  const auto dx = direction.dot(localXAxis);
304  const auto dy = direction.dot(localYAxis);
305  const auto dz = direction.dot(localZAxis);
306  // The normalization factor
307  const auto norm = 1 / (1 - dz * dz);
308  // The direction transpose
309  const auto& dirRowVec = direction.transpose();
310  // The derivative of path w.r.t. the local axes
311  // @note The following calculations assume that the intersection of the track
312  // with the cylinder always satisfy: perp(localPos) = R
313  const auto localXAxisToPath =
314  (-2 * norm * (dx * pcRowVec + localPos.x() * dirRowVec)).eval();
315  const auto localYAxisToPath =
316  (-2 * norm * (dy * pcRowVec + localPos.y() * dirRowVec)).eval();
317  const auto localZAxisToPath =
318  (-4 * norm * norm * (dx * localPos.x() + dy * localPos.y()) * dz *
319  dirRowVec)
320  .eval();
321  // Calculate the derivative of local frame axes w.r.t its rotation
322  const auto [rotToLocalXAxis, rotToLocalYAxis, rotToLocalZAxis] =
324  // Initialize the derivative of propagation path w.r.t. local frame
325  // translation (origin) and rotation
326  AlignmentToPathMatrix alignToPath = AlignmentToPathMatrix::Zero();
327  alignToPath.segment<3>(eAlignmentCenter0) =
328  2 * norm * (dx * localXAxis.transpose() + dy * localYAxis.transpose());
329  alignToPath.segment<3>(eAlignmentRotation0) =
330  localXAxisToPath * rotToLocalXAxis + localYAxisToPath * rotToLocalYAxis +
331  localZAxisToPath * rotToLocalZAxis;
332 
333  return alignToPath;
334 }
335 
338  const GeometryContext& gctx, const Vector3& position) const {
339  using VectorHelpers::perp;
340  using VectorHelpers::phi;
341  // The local frame transform
342  const auto& sTransform = transform(gctx);
343  // calculate the transformation to local coordinates
344  const Vector3 localPos = sTransform.inverse() * position;
345  const double lr = perp(localPos);
346  const double lphi = phi(localPos);
347  const double lcphi = std::cos(lphi);
348  const double lsphi = std::sin(lphi);
349  // Solve for radius R
350  double R = bounds().get(CylinderBounds::eR);
351  ActsMatrix<2, 3> loc3DToLocBound = ActsMatrix<2, 3>::Zero();
352  loc3DToLocBound << -R * lsphi / lr, R * lcphi / lr, 0, 0, 0, 1;
353 
354  return loc3DToLocBound;
355 }