Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:09:40

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2016-2020 CERN for the benefit of the Acts project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Surfaces/ConeSurface.hpp"
0010 
0011 #include "Acts/Geometry/GeometryObject.hpp"
0012 #include "Acts/Surfaces/SurfaceError.hpp"
0013 #include "Acts/Surfaces/detail/AlignmentHelper.hpp"
0014 #include "Acts/Surfaces/detail/FacesHelper.hpp"
0015 #include "Acts/Surfaces/detail/VerticesHelper.hpp"
0016 #include "Acts/Utilities/Helpers.hpp"
0017 #include "Acts/Utilities/Intersection.hpp"
0018 #include "Acts/Utilities/ThrowAssert.hpp"
0019 #include "Acts/Utilities/detail/RealQuadraticEquation.hpp"
0020 
0021 #include <algorithm>
0022 #include <cmath>
0023 #include <limits>
0024 #include <stdexcept>
0025 #include <utility>
0026 #include <vector>
0027 
0028 using Acts::VectorHelpers::perp;
0029 using Acts::VectorHelpers::phi;
0030 
0031 Acts::ConeSurface::ConeSurface(const ConeSurface& other)
0032     : GeometryObject(), RegularSurface(other), m_bounds(other.m_bounds) {}
0033 
0034 Acts::ConeSurface::ConeSurface(const GeometryContext& gctx,
0035                                const ConeSurface& other,
0036                                const Transform3& shift)
0037     : GeometryObject(),
0038       RegularSurface(gctx, other, shift),
0039       m_bounds(other.m_bounds) {}
0040 
0041 Acts::ConeSurface::ConeSurface(const Transform3& transform, double alpha,
0042                                bool symmetric)
0043     : GeometryObject(),
0044       RegularSurface(transform),
0045       m_bounds(std::make_shared<const ConeBounds>(alpha, symmetric)) {}
0046 
0047 Acts::ConeSurface::ConeSurface(const Transform3& transform, double alpha,
0048                                double zmin, double zmax, double halfPhi)
0049     : GeometryObject(),
0050       RegularSurface(transform),
0051       m_bounds(std::make_shared<const ConeBounds>(alpha, zmin, zmax, halfPhi)) {
0052 }
0053 
0054 Acts::ConeSurface::ConeSurface(const Transform3& transform,
0055                                std::shared_ptr<const ConeBounds> cbounds)
0056     : GeometryObject(),
0057       RegularSurface(transform),
0058       m_bounds(std::move(cbounds)) {
0059   throw_assert(m_bounds, "ConeBounds must not be nullptr");
0060 }
0061 
0062 Acts::Vector3 Acts::ConeSurface::binningPosition(
0063     const GeometryContext& gctx, Acts::BinningValue bValue) const {
0064   const Vector3& sfCenter = center(gctx);
0065 
0066   // special binning type for R-type methods
0067   if (bValue == Acts::binR || bValue == Acts::binRPhi) {
0068     return Vector3(sfCenter.x() + bounds().r(sfCenter.z()), sfCenter.y(),
0069                    sfCenter.z());
0070   }
0071   // give the center as default for all of these binning types
0072   // binX, binY, binZ, binR, binPhi, binRPhi, binH, binEta
0073   return sfCenter;
0074 }
0075 
0076 Acts::Surface::SurfaceType Acts::ConeSurface::type() const {
0077   return Surface::Cone;
0078 }
0079 
0080 Acts::ConeSurface& Acts::ConeSurface::operator=(const ConeSurface& other) {
0081   if (this != &other) {
0082     Surface::operator=(other);
0083     m_bounds = other.m_bounds;
0084   }
0085   return *this;
0086 }
0087 
0088 Acts::Vector3 Acts::ConeSurface::rotSymmetryAxis(
0089     const GeometryContext& gctx) const {
0090   return transform(gctx).matrix().block<3, 1>(0, 2);
0091 }
0092 
0093 Acts::RotationMatrix3 Acts::ConeSurface::referenceFrame(
0094     const GeometryContext& gctx, const Vector3& position,
0095     const Vector3& /*direction*/) const {
0096   RotationMatrix3 mFrame;
0097   // construct the measurement frame
0098   // measured Y is the local z axis
0099   Vector3 measY = rotSymmetryAxis(gctx);
0100   // measured z is the position transverse normalized
0101   Vector3 measDepth = Vector3(position.x(), position.y(), 0.).normalized();
0102   // measured X is what comoes out of it
0103   Acts::Vector3 measX(measY.cross(measDepth).normalized());
0104   // the columnes
0105   mFrame.col(0) = measX;
0106   mFrame.col(1) = measY;
0107   mFrame.col(2) = measDepth;
0108   // return the rotation matrix
0109   //!< @todo fold in alpha
0110   // return it
0111   return mFrame;
0112 }
0113 
0114 Acts::Vector3 Acts::ConeSurface::localToGlobal(const GeometryContext& gctx,
0115                                                const Vector2& lposition) const {
0116   // create the position in the local 3d frame
0117   double r = lposition[Acts::eBoundLoc1] * bounds().tanAlpha();
0118   double phi = lposition[Acts::eBoundLoc0] / r;
0119   Vector3 loc3Dframe(r * cos(phi), r * sin(phi), lposition[Acts::eBoundLoc1]);
0120   return transform(gctx) * loc3Dframe;
0121 }
0122 
0123 Acts::Result<Acts::Vector2> Acts::ConeSurface::globalToLocal(
0124     const GeometryContext& gctx, const Vector3& position,
0125     double tolerance) const {
0126   Vector3 loc3Dframe = transform(gctx).inverse() * position;
0127   double r = loc3Dframe.z() * bounds().tanAlpha();
0128   if (std::abs(perp(loc3Dframe) - r) > tolerance) {
0129     return Result<Vector2>::failure(SurfaceError::GlobalPositionNotOnSurface);
0130   }
0131   return Result<Acts::Vector2>::success(
0132       Vector2(r * atan2(loc3Dframe.y(), loc3Dframe.x()), loc3Dframe.z()));
0133 }
0134 
0135 double Acts::ConeSurface::pathCorrection(const GeometryContext& gctx,
0136                                          const Vector3& position,
0137                                          const Vector3& direction) const {
0138   // (cos phi cos alpha, sin phi cos alpha, sgn z sin alpha)
0139   Vector3 posLocal = transform(gctx).inverse() * position;
0140   double phi = VectorHelpers::phi(posLocal);
0141   double sgn = posLocal.z() > 0. ? -1. : +1.;
0142   double cosAlpha = std::cos(bounds().get(ConeBounds::eAlpha));
0143   double sinAlpha = std::sin(bounds().get(ConeBounds::eAlpha));
0144   Vector3 normalC(cos(phi) * cosAlpha, sin(phi) * cosAlpha, sgn * sinAlpha);
0145   normalC = transform(gctx) * normalC;
0146   // Back to the global frame
0147   double cAlpha = normalC.dot(direction);
0148   return std::abs(1. / cAlpha);
0149 }
0150 
0151 std::string Acts::ConeSurface::name() const {
0152   return "Acts::ConeSurface";
0153 }
0154 
0155 Acts::Vector3 Acts::ConeSurface::normal(const GeometryContext& gctx,
0156                                         const Acts::Vector2& lposition) const {
0157   // (cos phi cos alpha, sin phi cos alpha, sgn z sin alpha)
0158   double phi = lposition[Acts::eBoundLoc0] /
0159                (bounds().r(lposition[Acts::eBoundLoc1])),
0160          sgn = lposition[Acts::eBoundLoc1] > 0 ? -1. : +1.;
0161   double cosAlpha = std::cos(bounds().get(ConeBounds::eAlpha));
0162   double sinAlpha = std::sin(bounds().get(ConeBounds::eAlpha));
0163   Vector3 localNormal(cos(phi) * cosAlpha, sin(phi) * cosAlpha, sgn * sinAlpha);
0164   return Vector3(transform(gctx).linear() * localNormal);
0165 }
0166 
0167 Acts::Vector3 Acts::ConeSurface::normal(const GeometryContext& gctx,
0168                                         const Acts::Vector3& position) const {
0169   // get it into the cylinder frame if needed
0170   // @todo respect opening angle
0171   Vector3 pos3D = transform(gctx).inverse() * position;
0172   pos3D.z() = 0;
0173   return pos3D.normalized();
0174 }
0175 
0176 const Acts::ConeBounds& Acts::ConeSurface::bounds() const {
0177   // is safe because no constructor w/o bounds exists
0178   return (*m_bounds.get());
0179 }
0180 
0181 Acts::Polyhedron Acts::ConeSurface::polyhedronRepresentation(
0182     const GeometryContext& gctx, std::size_t lseg) const {
0183   // Prepare vertices and faces
0184   std::vector<Vector3> vertices;
0185   std::vector<Polyhedron::FaceType> faces;
0186   std::vector<Polyhedron::FaceType> triangularMesh;
0187 
0188   double minZ = bounds().get(ConeBounds::eMinZ);
0189   double maxZ = bounds().get(ConeBounds::eMaxZ);
0190 
0191   if (minZ == -std::numeric_limits<double>::infinity() ||
0192       maxZ == std::numeric_limits<double>::infinity()) {
0193     throw std::domain_error(
0194         "Polyhedron repr of boundless surface not possible");
0195   }
0196 
0197   auto ctransform = transform(gctx);
0198 
0199   // The tip - created only once and only, if it is not a cut-off cone
0200   bool tipExists = false;
0201   if (minZ * maxZ <= s_onSurfaceTolerance) {
0202     vertices.push_back(ctransform * Vector3(0., 0., 0.));
0203     tipExists = true;
0204   }
0205 
0206   // Cone parameters
0207   double hPhiSec = bounds().get(ConeBounds::eHalfPhiSector);
0208   double avgPhi = bounds().get(ConeBounds::eAveragePhi);
0209   bool fullCone = (hPhiSec == M_PI);
0210 
0211   // Get the phi segments from the helper
0212   auto phiSegs = fullCone ? detail::VerticesHelper::phiSegments()
0213                           : detail::VerticesHelper::phiSegments(
0214                                 avgPhi - hPhiSec, avgPhi + hPhiSec,
0215                                 {static_cast<ActsScalar>(avgPhi)});
0216 
0217   // Negative cone if exists
0218   std::vector<double> coneSides;
0219   if (std::abs(minZ) > s_onSurfaceTolerance) {
0220     coneSides.push_back(minZ);
0221   }
0222   if (std::abs(maxZ) > s_onSurfaceTolerance) {
0223     coneSides.push_back(maxZ);
0224   }
0225   for (auto& z : coneSides) {
0226     // Remember the first vertex
0227     std::size_t firstIv = vertices.size();
0228     // Radius and z offset
0229     double r = std::abs(z) * bounds().tanAlpha();
0230     Vector3 zoffset(0., 0., z);
0231     for (unsigned int iseg = 0; iseg < phiSegs.size() - 1; ++iseg) {
0232       int addon = (iseg == phiSegs.size() - 2 && !fullCone) ? 1 : 0;
0233       detail::VerticesHelper::createSegment(vertices, {r, r}, phiSegs[iseg],
0234                                             phiSegs[iseg + 1], lseg, addon,
0235                                             zoffset, ctransform);
0236     }
0237     // Create the faces
0238     if (tipExists) {
0239       for (std::size_t iv = firstIv + 2; iv < vertices.size() + 1; ++iv) {
0240         std::size_t one = 0, two = iv - 1, three = iv - 2;
0241         if (z < 0.) {
0242           std::swap(two, three);
0243         }
0244         faces.push_back({one, two, three});
0245       }
0246       // Complete cone if necessary
0247       if (fullCone) {
0248         if (z > 0.) {
0249           faces.push_back({0, firstIv, vertices.size() - 1});
0250         } else {
0251           faces.push_back({0, vertices.size() - 1, firstIv});
0252         }
0253       }
0254     }
0255   }
0256   // if no tip exists, connect the two bows
0257   if (tipExists) {
0258     triangularMesh = faces;
0259   } else {
0260     auto facesMesh =
0261         detail::FacesHelper::cylindricalFaceMesh(vertices, fullCone);
0262     faces = facesMesh.first;
0263     triangularMesh = facesMesh.second;
0264   }
0265   return Polyhedron(vertices, faces, triangularMesh, false);
0266 }
0267 
0268 Acts::detail::RealQuadraticEquation Acts::ConeSurface::intersectionSolver(
0269     const GeometryContext& gctx, const Vector3& position,
0270     const Vector3& direction) const {
0271   // Transform into the local frame
0272   Transform3 invTrans = transform(gctx).inverse();
0273   Vector3 point1 = invTrans * position;
0274   Vector3 dir1 = invTrans.linear() * direction;
0275 
0276   // See file header for the formula derivation
0277   double tan2Alpha = bounds().tanAlpha() * bounds().tanAlpha(),
0278          A = dir1.x() * dir1.x() + dir1.y() * dir1.y() -
0279              tan2Alpha * dir1.z() * dir1.z(),
0280          B = 2 * (dir1.x() * point1.x() + dir1.y() * point1.y() -
0281                   tan2Alpha * dir1.z() * point1.z()),
0282          C = point1.x() * point1.x() + point1.y() * point1.y() -
0283              tan2Alpha * point1.z() * point1.z();
0284   if (A == 0.) {
0285     A += 1e-16;  // avoid division by zero
0286   }
0287 
0288   return detail::RealQuadraticEquation(A, B, C);
0289 }
0290 
0291 Acts::SurfaceMultiIntersection Acts::ConeSurface::intersect(
0292     const GeometryContext& gctx, const Vector3& position,
0293     const Vector3& direction, const BoundaryCheck& bcheck,
0294     ActsScalar tolerance) const {
0295   // Solve the quadratic equation
0296   auto qe = intersectionSolver(gctx, position, direction);
0297 
0298   // If no valid solution return a non-valid surfaceIntersection
0299   if (qe.solutions == 0) {
0300     return {{Intersection3D::invalid(), Intersection3D::invalid()}, this};
0301   }
0302 
0303   // Check the validity of the first solution
0304   Vector3 solution1 = position + qe.first * direction;
0305   Intersection3D::Status status1 = std::abs(qe.first) < std::abs(tolerance)
0306                                        ? Intersection3D::Status::onSurface
0307                                        : Intersection3D::Status::reachable;
0308 
0309   if (bcheck.isEnabled() && !isOnSurface(gctx, solution1, direction, bcheck)) {
0310     status1 = Intersection3D::Status::missed;
0311   }
0312 
0313   // Check the validity of the second solution
0314   Vector3 solution2 = position + qe.first * direction;
0315   Intersection3D::Status status2 = std::abs(qe.second) < std::abs(tolerance)
0316                                        ? Intersection3D::Status::onSurface
0317                                        : Intersection3D::Status::reachable;
0318   if (bcheck.isEnabled() && !isOnSurface(gctx, solution2, direction, bcheck)) {
0319     status2 = Intersection3D::Status::missed;
0320   }
0321 
0322   const auto& tf = transform(gctx);
0323   // Set the intersection
0324   Intersection3D first(tf * solution1, qe.first, status1);
0325   Intersection3D second(tf * solution2, qe.second, status2);
0326   // Order based on path length
0327   if (first.pathLength() <= second.pathLength()) {
0328     return {{first, second}, this};
0329   }
0330   return {{second, first}, this};
0331 }
0332 
0333 Acts::AlignmentToPathMatrix Acts::ConeSurface::alignmentToPathDerivative(
0334     const GeometryContext& gctx, const Vector3& position,
0335     const Vector3& direction) const {
0336   assert(isOnSurface(gctx, position, direction, BoundaryCheck(false)));
0337 
0338   // The vector between position and center
0339   const auto pcRowVec = (position - center(gctx)).transpose().eval();
0340   // The rotation
0341   const auto& rotation = transform(gctx).rotation();
0342   // The local frame x/y/z axis
0343   const auto& localXAxis = rotation.col(0);
0344   const auto& localYAxis = rotation.col(1);
0345   const auto& localZAxis = rotation.col(2);
0346   // The local coordinates
0347   const auto localPos = (rotation.transpose() * position).eval();
0348   const auto dx = direction.dot(localXAxis);
0349   const auto dy = direction.dot(localYAxis);
0350   const auto dz = direction.dot(localZAxis);
0351   // The normalization factor
0352   const auto tanAlpha2 = bounds().tanAlpha() * bounds().tanAlpha();
0353   const auto norm = 1 / (1 - dz * dz * (1 + tanAlpha2));
0354   // The direction transpose
0355   const auto& dirRowVec = direction.transpose();
0356   // The derivative of path w.r.t. the local axes
0357   // @note The following calculations assume that the intersection of the track
0358   // with the cone always satisfy: localPos.z()*tanAlpha =perp(localPos)
0359   const auto localXAxisToPath =
0360       (-2 * norm * (dx * pcRowVec + localPos.x() * dirRowVec)).eval();
0361   const auto localYAxisToPath =
0362       (-2 * norm * (dy * pcRowVec + localPos.y() * dirRowVec)).eval();
0363   const auto localZAxisToPath =
0364       (2 * norm * tanAlpha2 * (dz * pcRowVec + localPos.z() * dirRowVec) -
0365        4 * norm * norm * (1 + tanAlpha2) *
0366            (dx * localPos.x() + dy * localPos.y() -
0367             dz * localPos.z() * tanAlpha2) *
0368            dz * dirRowVec)
0369           .eval();
0370   // Calculate the derivative of local frame axes w.r.t its rotation
0371   const auto [rotToLocalXAxis, rotToLocalYAxis, rotToLocalZAxis] =
0372       detail::rotationToLocalAxesDerivative(rotation);
0373   // Initialize the derivative of propagation path w.r.t. local frame
0374   // translation (origin) and rotation
0375   AlignmentToPathMatrix alignToPath = AlignmentToPathMatrix::Zero();
0376   alignToPath.segment<3>(eAlignmentCenter0) =
0377       2 * norm * (dx * localXAxis.transpose() + dy * localYAxis.transpose());
0378   alignToPath.segment<3>(eAlignmentRotation0) =
0379       localXAxisToPath * rotToLocalXAxis + localYAxisToPath * rotToLocalYAxis +
0380       localZAxisToPath * rotToLocalZAxis;
0381 
0382   return alignToPath;
0383 }
0384 
0385 Acts::ActsMatrix<2, 3> Acts::ConeSurface::localCartesianToBoundLocalDerivative(
0386     const GeometryContext& gctx, const Vector3& position) const {
0387   using VectorHelpers::perp;
0388   using VectorHelpers::phi;
0389   // The local frame transform
0390   const auto& sTransform = transform(gctx);
0391   // calculate the transformation to local coordinates
0392   const Vector3 localPos = sTransform.inverse() * position;
0393   const double lr = perp(localPos);
0394   const double lphi = phi(localPos);
0395   const double lcphi = std::cos(lphi);
0396   const double lsphi = std::sin(lphi);
0397   // Solve for radius R
0398   const double R = localPos.z() * bounds().tanAlpha();
0399   ActsMatrix<2, 3> loc3DToLocBound = ActsMatrix<2, 3>::Zero();
0400   loc3DToLocBound << -R * lsphi / lr, R * lcphi / lr,
0401       lphi * bounds().tanAlpha(), 0, 0, 1;
0402 
0403   return loc3DToLocBound;
0404 }