Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DiscSurface.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file DiscSurface.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2016-2021 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 
25 
26 #include <algorithm>
27 #include <cmath>
28 #include <stdexcept>
29 #include <utility>
30 #include <vector>
31 
34 
35 Acts::DiscSurface::DiscSurface(const DiscSurface& other)
36  : GeometryObject(), Surface(other), m_bounds(other.m_bounds) {}
37 
38 Acts::DiscSurface::DiscSurface(const GeometryContext& gctx,
39  const DiscSurface& other,
40  const Transform3& shift)
41  : GeometryObject(), Surface(gctx, other, shift), m_bounds(other.m_bounds) {}
42 
43 Acts::DiscSurface::DiscSurface(const Transform3& transform, double rmin,
44  double rmax, double hphisec)
45  : GeometryObject(),
46  Surface(transform),
47  m_bounds(std::make_shared<const RadialBounds>(rmin, rmax, hphisec)) {}
48 
49 Acts::DiscSurface::DiscSurface(const Transform3& transform, double minhalfx,
50  double maxhalfx, double minR, double maxR,
51  double avephi, double stereo)
52  : GeometryObject(),
53  Surface(transform),
54  m_bounds(std::make_shared<const DiscTrapezoidBounds>(
55  minhalfx, maxhalfx, minR, maxR, avephi, stereo)) {}
56 
57 Acts::DiscSurface::DiscSurface(const Transform3& transform,
58  std::shared_ptr<const DiscBounds> dbounds)
59  : GeometryObject(), Surface(transform), m_bounds(std::move(dbounds)) {}
60 
61 Acts::DiscSurface::DiscSurface(std::shared_ptr<const DiscBounds> dbounds,
62  const DetectorElementBase& detelement)
63  : GeometryObject(), Surface(detelement), m_bounds(std::move(dbounds)) {
64  throw_assert(m_bounds, "nullptr as DiscBounds");
65 }
66 
67 Acts::DiscSurface& Acts::DiscSurface::operator=(const DiscSurface& other) {
68  if (this != &other) {
70  m_bounds = other.m_bounds;
71  }
72  return *this;
73 }
74 
76  return Surface::Disc;
77 }
78 
79 Acts::Vector3 Acts::DiscSurface::localToGlobal(const GeometryContext& gctx,
80  const Vector2& lposition,
81  const Vector3& /*gmom*/) const {
82  // create the position in the local 3d frame
83  Vector3 loc3Dframe(
84  lposition[Acts::eBoundLoc0] * cos(lposition[Acts::eBoundLoc1]),
85  lposition[Acts::eBoundLoc0] * sin(lposition[Acts::eBoundLoc1]), 0.);
86  // transform to globalframe
87  return transform(gctx) * loc3Dframe;
88 }
89 
90 Acts::Result<Acts::Vector2> Acts::DiscSurface::globalToLocal(
91  const GeometryContext& gctx, const Vector3& position,
92  const Vector3& /*gmom*/, double tolerance) const {
93  // transport it to the globalframe
94  Vector3 loc3Dframe = (transform(gctx).inverse()) * position;
95  if (std::abs(loc3Dframe.z()) > std::abs(tolerance)) {
96  return Result<Vector2>::failure(SurfaceError::GlobalPositionNotOnSurface);
97  }
98  return Result<Acts::Vector2>::success({perp(loc3Dframe), phi(loc3Dframe)});
99 }
100 
101 Acts::Vector2 Acts::DiscSurface::localPolarToLocalCartesian(
102  const Vector2& locpol) const {
103  const DiscTrapezoidBounds* dtbo =
104  dynamic_cast<const Acts::DiscTrapezoidBounds*>(&(bounds()));
105  if (dtbo != nullptr) {
106  double rMedium = dtbo->rCenter();
107  double phi = dtbo->get(DiscTrapezoidBounds::eAveragePhi);
108 
109  Vector2 polarCenter(rMedium, phi);
110  Vector2 cartCenter = localPolarToCartesian(polarCenter);
111  Vector2 cartPos = localPolarToCartesian(locpol);
112  Vector2 Pos = cartPos - cartCenter;
113 
114  Acts::Vector2 locPos(
115  Pos[Acts::eBoundLoc0] * sin(phi) - Pos[Acts::eBoundLoc1] * cos(phi),
116  Pos[Acts::eBoundLoc1] * sin(phi) + Pos[Acts::eBoundLoc0] * cos(phi));
117  return Vector2(locPos[Acts::eBoundLoc0], locPos[Acts::eBoundLoc1]);
118  }
119  return Vector2(locpol[Acts::eBoundLoc0] * cos(locpol[Acts::eBoundLoc1]),
120  locpol[Acts::eBoundLoc0] * sin(locpol[Acts::eBoundLoc1]));
121 }
122 
123 Acts::Vector3 Acts::DiscSurface::localCartesianToGlobal(
124  const GeometryContext& gctx, const Vector2& lposition) const {
125  Vector3 loc3Dframe(lposition[Acts::eBoundLoc0], lposition[Acts::eBoundLoc1],
126  0.);
127  return Vector3(transform(gctx) * loc3Dframe);
128 }
129 
130 Acts::Vector2 Acts::DiscSurface::globalToLocalCartesian(
131  const GeometryContext& gctx, const Vector3& position,
132  double /*direction*/) const {
133  Vector3 loc3Dframe = (transform(gctx).inverse()) * position;
134  return Vector2(loc3Dframe.x(), loc3Dframe.y());
135 }
136 
138  return "Acts::DiscSurface";
139 }
140 
142  if (m_bounds) {
143  return (*(m_bounds.get()));
144  }
145  return s_noBounds;
146 }
147 
148 Acts::Polyhedron Acts::DiscSurface::polyhedronRepresentation(
149  const GeometryContext& gctx, size_t lseg) const {
150  // Prepare vertices and faces
151  std::vector<Vector3> vertices;
152  std::vector<Polyhedron::FaceType> faces;
153  std::vector<Polyhedron::FaceType> triangularMesh;
154 
155  // Understand the disc
156  bool fullDisc = m_bounds->coversFullAzimuth();
157  bool toCenter = m_bounds->rMin() < s_onSurfaceTolerance;
158  // If you have bounds you can create a polyhedron representation
159  bool exactPolyhedron = (m_bounds->type() == SurfaceBounds::eDiscTrapezoid);
160  bool addCentreFromConvexFace = (m_bounds->type() != SurfaceBounds::eAnnulus);
161  if (m_bounds) {
162  auto vertices2D = m_bounds->vertices(lseg);
163  vertices.reserve(vertices2D.size() + 1);
164  Vector3 wCenter(0., 0., 0);
165  for (const auto& v2D : vertices2D) {
166  vertices.push_back(transform(gctx) * Vector3(v2D.x(), v2D.y(), 0.));
167  wCenter += (*vertices.rbegin());
168  }
169  // These are convex shapes, use the helper method
170  // For rings there's a sweet spot when this stops working
171  if (exactPolyhedron or toCenter or not fullDisc) {
172  // Transform them into the vertex frame
173  wCenter *= 1. / vertices.size();
174  if (addCentreFromConvexFace) {
175  vertices.push_back(wCenter);
176  }
177  auto facesMesh = detail::FacesHelper::convexFaceMesh(vertices, true);
178  faces = facesMesh.first;
179  triangularMesh = facesMesh.second;
180  } else {
181  // Two concentric rings, we use the pure concentric method momentarily,
182  // but that creates too many unneccesarry faces, when only two
183  // are needed to describe the mesh, @todo investigate merging flag
184  auto facesMesh = detail::FacesHelper::cylindricalFaceMesh(vertices, true);
185  faces = facesMesh.first;
186  triangularMesh = facesMesh.second;
187  }
188  } else {
189  throw std::domain_error(
190  "Polyhedron repr of boundless surface not possible.");
191  }
192  return Polyhedron(vertices, faces, triangularMesh, exactPolyhedron);
193 }
194 
195 Acts::Vector2 Acts::DiscSurface::localPolarToCartesian(
196  const Vector2& lpolar) const {
197  return Vector2(lpolar[eBoundLoc0] * cos(lpolar[eBoundLoc1]),
198  lpolar[eBoundLoc0] * sin(lpolar[eBoundLoc1]));
199 }
200 
201 Acts::Vector2 Acts::DiscSurface::localCartesianToPolar(
202  const Vector2& lcart) const {
203  return Vector2(std::hypot(lcart[eBoundLoc0], lcart[eBoundLoc1]),
204  std::atan2(lcart[eBoundLoc1], lcart[eBoundLoc0]));
205 }
206 
207 Acts::BoundToFreeMatrix Acts::DiscSurface::boundToFreeJacobian(
208  const GeometryContext& gctx, const BoundVector& boundParams) const {
209  // Transform from bound to free parameters
210  FreeVector freeParams =
211  detail::transformBoundToFreeParameters(*this, gctx, boundParams);
212  // The global position
213  const Vector3 position = freeParams.segment<3>(eFreePos0);
214  // The direction
215  const Vector3 direction = freeParams.segment<3>(eFreeDir0);
216  // Get the sines and cosines directly
217  const double cos_theta = std::cos(boundParams[eBoundTheta]);
218  const double sin_theta = std::sin(boundParams[eBoundTheta]);
219  const double cos_phi = std::cos(boundParams[eBoundPhi]);
220  const double sin_phi = std::sin(boundParams[eBoundPhi]);
221  // special polar coordinates for the Disc
222  double lrad = boundParams[eBoundLoc0];
223  double lphi = boundParams[eBoundLoc1];
224  double lcos_phi = cos(lphi);
225  double lsin_phi = sin(lphi);
226  // retrieve the reference frame
227  const auto rframe = referenceFrame(gctx, position, direction);
228  // Initialize the jacobian from local to global
229  BoundToFreeMatrix jacToGlobal = BoundToFreeMatrix::Zero();
230  // the local error components - rotated from reference frame
231  jacToGlobal.block<3, 1>(eFreePos0, eBoundLoc0) =
232  lcos_phi * rframe.block<3, 1>(0, 0) + lsin_phi * rframe.block<3, 1>(0, 1);
233  jacToGlobal.block<3, 1>(eFreePos0, eBoundLoc1) =
234  lrad * (lcos_phi * rframe.block<3, 1>(0, 1) -
235  lsin_phi * rframe.block<3, 1>(0, 0));
236  // the time component
237  jacToGlobal(eFreeTime, eBoundTime) = 1;
238  // the momentum components
239  jacToGlobal(eFreeDir0, eBoundPhi) = (-sin_theta) * sin_phi;
240  jacToGlobal(eFreeDir0, eBoundTheta) = cos_theta * cos_phi;
241  jacToGlobal(eFreeDir1, eBoundPhi) = sin_theta * cos_phi;
242  jacToGlobal(eFreeDir1, eBoundTheta) = cos_theta * sin_phi;
243  jacToGlobal(eFreeDir2, eBoundTheta) = (-sin_theta);
244  jacToGlobal(eFreeQOverP, eBoundQOverP) = 1;
245  return jacToGlobal;
246 }
247 
248 Acts::FreeToBoundMatrix Acts::DiscSurface::freeToBoundJacobian(
249  const GeometryContext& gctx, const FreeVector& parameters) const {
250  using VectorHelpers::perp;
251  using VectorHelpers::phi;
252  // The global position
253  const auto position = parameters.segment<3>(eFreePos0);
254  // The direction
255  const auto direction = parameters.segment<3>(eFreeDir0);
256  // Optimized trigonometry on the propagation direction
257  const double x = direction(0); // == cos(phi) * sin(theta)
258  const double y = direction(1); // == sin(phi) * sin(theta)
259  const double z = direction(2); // == cos(theta)
260  // can be turned into cosine/sine
261  const double cosTheta = z;
262  const double sinTheta = std::hypot(x, y);
263  const double invSinTheta = 1. / sinTheta;
264  const double cosPhi = x * invSinTheta;
265  const double sinPhi = y * invSinTheta;
266  // The measurement frame of the surface
267  RotationMatrix3 rframeT =
268  referenceFrame(gctx, position, direction).transpose();
269  // calculate the transformation to local coordinates
270  const Vector3 pos_loc = transform(gctx).inverse() * position;
271  const double lr = perp(pos_loc);
272  const double lphi = phi(pos_loc);
273  const double lcphi = cos(lphi);
274  const double lsphi = sin(lphi);
275  // rotate into the polar coorindates
276  auto lx = rframeT.block<1, 3>(0, 0);
277  auto ly = rframeT.block<1, 3>(1, 0);
278  // Initialize the jacobian from global to local
279  FreeToBoundMatrix jacToLocal = FreeToBoundMatrix::Zero();
280  // Local position component
281  jacToLocal.block<1, 3>(eBoundLoc0, eFreePos0) = lcphi * lx + lsphi * ly;
282  jacToLocal.block<1, 3>(eBoundLoc1, eFreePos0) =
283  (lcphi * ly - lsphi * lx) / lr;
284  // Time element
285  jacToLocal(eBoundTime, eFreeTime) = 1;
286  // Directional and momentum elements for reference frame surface
287  jacToLocal(eBoundPhi, eFreeDir0) = -sinPhi * invSinTheta;
288  jacToLocal(eBoundPhi, eFreeDir1) = cosPhi * invSinTheta;
289  jacToLocal(eBoundTheta, eFreeDir0) = cosPhi * cosTheta;
290  jacToLocal(eBoundTheta, eFreeDir1) = sinPhi * cosTheta;
291  jacToLocal(eBoundTheta, eFreeDir2) = -sinTheta;
292  jacToLocal(eBoundQOverP, eFreeQOverP) = 1;
293  return jacToLocal;
294 }
295 
297  const GeometryContext& gctx, const Vector3& position,
298  const Vector3& direction, const BoundaryCheck& bcheck,
299  ActsScalar tolerance) const {
300  // Get the contextual transform
301  auto gctxTransform = transform(gctx);
302  // Use the intersection helper for planar surfaces
303  auto intersection =
304  PlanarHelper::intersect(gctxTransform, position, direction, tolerance);
305  auto status = intersection.status();
306  // Evaluate boundary check if requested (and reachable)
307  if (intersection.status() != Intersection3D::Status::unreachable and
308  bcheck and m_bounds != nullptr) {
309  // Built-in local to global for speed reasons
310  const auto& tMatrix = gctxTransform.matrix();
311  const Vector3 vecLocal(intersection.position() - tMatrix.block<3, 1>(0, 3));
312  const Vector2 lcartesian = tMatrix.block<3, 2>(0, 0).transpose() * vecLocal;
313  if (bcheck.type() == BoundaryCheck::Type::eAbsolute and
314  m_bounds->coversFullAzimuth()) {
315  double modifiedTolerance = tolerance + bcheck.tolerance()[eBoundLoc0];
316  if (not m_bounds->insideRadialBounds(VectorHelpers::perp(lcartesian),
317  modifiedTolerance)) {
318  status = Intersection3D::Status::missed;
319  }
320  } else if (not insideBounds(localCartesianToPolar(lcartesian), bcheck)) {
321  status = Intersection3D::Status::missed;
322  }
323  }
324  return {{Intersection3D(intersection.position(), intersection.pathLength(),
325  status),
327  this};
328 }
329 
330 Acts::ActsMatrix<2, 3> Acts::DiscSurface::localCartesianToBoundLocalDerivative(
331  const GeometryContext& gctx, const Vector3& position) const {
332  using VectorHelpers::perp;
333  using VectorHelpers::phi;
334  // The local frame transform
335  const auto& sTransform = transform(gctx);
336  // calculate the transformation to local coordinates
337  const Vector3 localPos = sTransform.inverse() * position;
338  const double lr = perp(localPos);
339  const double lphi = phi(localPos);
340  const double lcphi = std::cos(lphi);
341  const double lsphi = std::sin(lphi);
342  ActsMatrix<2, 3> loc3DToLocBound = ActsMatrix<2, 3>::Zero();
343  loc3DToLocBound << lcphi, lsphi, 0, -lsphi / lr, lcphi / lr, 0;
344 
345  return loc3DToLocBound;
346 }
347 
348 Acts::Vector3 Acts::DiscSurface::normal(const GeometryContext& gctx,
349  const Vector2& /*lposition*/) const {
350  // fast access via transform matrix (and not rotation())
351  const auto& tMatrix = transform(gctx).matrix();
352  return Vector3(tMatrix(0, 2), tMatrix(1, 2), tMatrix(2, 2));
353 }
354 
355 Acts::Vector3 Acts::DiscSurface::binningPosition(const GeometryContext& gctx,
356  BinningValue bValue) const {
357  if (bValue == binR || bValue == binPhi) {
358  double r = m_bounds->binningValueR();
359  double phi = m_bounds->binningValuePhi();
360  return localToGlobal(gctx, Vector2{r, phi}, Vector3{});
361  }
362  return center(gctx);
363 }
364 
365 double Acts::DiscSurface::binningPositionValue(const GeometryContext& gctx,
366  BinningValue bValue) const {
367  if (bValue == binR) {
368  return VectorHelpers::perp(binningPosition(gctx, bValue));
369  }
370  if (bValue == binPhi) {
371  return VectorHelpers::phi(binningPosition(gctx, bValue));
372  }
373 
374  return GeometryObject::binningPositionValue(gctx, bValue);
375 }
376 
377 double Acts::DiscSurface::pathCorrection(const GeometryContext& gctx,
378  const Vector3& position,
379  const Vector3& direction) const {
381  return 1. / std::abs(Surface::normal(gctx, position).dot(direction));
382 }