File indexing completed on 2025-08-06 08:11:28
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/data/test_case.hpp>
0010 #include <boost/test/tools/output_test_stream.hpp>
0011 #include <boost/test/unit_test.hpp>
0012
0013 #include "Acts/Definitions/Algebra.hpp"
0014 #include "Acts/Definitions/Tolerance.hpp"
0015 #include "Acts/Definitions/Units.hpp"
0016 #include "Acts/Geometry/Extent.hpp"
0017 #include "Acts/Geometry/GeometryContext.hpp"
0018 #include "Acts/Geometry/Polyhedron.hpp"
0019 #include "Acts/Surfaces/CylinderBounds.hpp"
0020 #include "Acts/Surfaces/CylinderSurface.hpp"
0021 #include "Acts/Surfaces/Surface.hpp"
0022 #include "Acts/Surfaces/SurfaceBounds.hpp"
0023 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0024 #include "Acts/Utilities/BinningType.hpp"
0025 #include "Acts/Utilities/Helpers.hpp"
0026 #include "Acts/Utilities/Intersection.hpp"
0027 #include "Acts/Utilities/Result.hpp"
0028
0029 #include <algorithm>
0030 #include <cmath>
0031 #include <initializer_list>
0032 #include <memory>
0033 #include <ostream>
0034 #include <string>
0035 #include <utility>
0036
0037 namespace Acts {
0038 class AssertionFailureException;
0039 }
0040
0041 namespace Acts::Test {
0042
0043
0044 GeometryContext testContext = GeometryContext();
0045
0046 BOOST_AUTO_TEST_SUITE(CylinderSurfaces)
0047
0048 BOOST_AUTO_TEST_CASE(CylinderSurfaceConstruction) {
0049
0050
0051
0052 double radius(1.0), halfZ(10.), halfPhiSector(M_PI / 8.);
0053 Translation3 translation{0., 1., 2.};
0054 auto pTransform = Transform3(translation);
0055 BOOST_CHECK_EQUAL(
0056 Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ)->type(),
0057 Surface::Cylinder);
0058
0059
0060 BOOST_CHECK_EQUAL(Surface::makeShared<CylinderSurface>(pTransform, radius,
0061 halfZ, halfPhiSector)
0062 ->type(),
0063 Surface::Cylinder);
0064
0065
0066 auto pCylinderBounds = std::make_shared<const CylinderBounds>(radius, halfZ);
0067 BOOST_CHECK_EQUAL(
0068 Surface::makeShared<CylinderSurface>(pTransform, pCylinderBounds)->type(),
0069 Surface::Cylinder);
0070
0071
0072
0073 auto cylinderSurfaceObject =
0074 Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ);
0075 auto copiedCylinderSurface =
0076 Surface::makeShared<CylinderSurface>(*cylinderSurfaceObject);
0077 BOOST_CHECK_EQUAL(copiedCylinderSurface->type(), Surface::Cylinder);
0078 BOOST_CHECK(*copiedCylinderSurface == *cylinderSurfaceObject);
0079
0080
0081 auto copiedTransformedCylinderSurface = Surface::makeShared<CylinderSurface>(
0082 testContext, *cylinderSurfaceObject, pTransform);
0083 BOOST_CHECK_EQUAL(copiedTransformedCylinderSurface->type(),
0084 Surface::Cylinder);
0085
0086
0087 BOOST_CHECK_THROW(auto nullBounds = Surface::makeShared<CylinderSurface>(
0088 Transform3::Identity(), nullptr),
0089 AssertionFailureException);
0090 }
0091
0092
0093 BOOST_AUTO_TEST_CASE(CylinderSurfaceProperties) {
0094
0095 double radius(1.0), halfZ(10.);
0096 Translation3 translation{0., 1., 2.};
0097 auto pTransform = Transform3(translation);
0098 auto cylinderSurfaceObject =
0099 Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ);
0100
0101
0102 BOOST_CHECK_EQUAL(cylinderSurfaceObject->type(), Surface::Cylinder);
0103
0104
0105 Vector3 binningPosition{0., 1., 2.};
0106 CHECK_CLOSE_ABS(
0107 cylinderSurfaceObject->binningPosition(testContext, BinningValue::binPhi),
0108 binningPosition, 1e-9);
0109
0110
0111 double rootHalf = std::sqrt(0.5);
0112 Vector3 globalPosition{rootHalf, 1. - rootHalf, 0.};
0113 Vector3 globalPositionZ{rootHalf, 1. - rootHalf, 2.0};
0114 Vector3 momentum{15., 15., 15.};
0115 Vector3 momentum2{6.6, -3., 2.};
0116 RotationMatrix3 expectedFrame;
0117 expectedFrame << rootHalf, 0., rootHalf, rootHalf, 0., -rootHalf, 0., 1., 0.;
0118
0119 CHECK_CLOSE_OR_SMALL(cylinderSurfaceObject->referenceFrame(
0120 testContext, globalPosition, momentum),
0121 expectedFrame, 1e-6, 1e-9);
0122
0123 CHECK_CLOSE_OR_SMALL(cylinderSurfaceObject->referenceFrame(
0124 testContext, globalPositionZ, momentum2),
0125 expectedFrame, 1e-6, 1e-9);
0126
0127
0128 Vector3 origin{0., 0., 0.};
0129 Vector3 normal3D = {0., -1., 0.};
0130 CHECK_CLOSE_ABS(cylinderSurfaceObject->normal(testContext, origin), normal3D,
0131 1e-9);
0132
0133 Vector3 pos45deg = {rootHalf, 1 + rootHalf, 0.};
0134 Vector3 pos45degZ = {rootHalf, 1 + rootHalf, 4.};
0135 Vector3 normal45deg = {rootHalf, rootHalf, 0.};
0136
0137 CHECK_CLOSE_ABS(cylinderSurfaceObject->normal(testContext, pos45deg),
0138 normal45deg, 1e-6 * rootHalf);
0139
0140 CHECK_CLOSE_ABS(cylinderSurfaceObject->normal(testContext, pos45degZ),
0141 normal45deg, 1e-6 * rootHalf);
0142
0143
0144 Vector2 positionPiBy2(1.0, 0.);
0145 Vector3 normalAtPiBy2{std::cos(1.), std::sin(1.), 0.};
0146 CHECK_CLOSE_ABS(cylinderSurfaceObject->normal(testContext, positionPiBy2),
0147 normalAtPiBy2, 1e-9);
0148
0149
0150
0151 Vector3 symmetryAxis{0., 0., 1.};
0152 CHECK_CLOSE_ABS(cylinderSurfaceObject->rotSymmetryAxis(testContext),
0153 symmetryAxis, 1e-9);
0154
0155
0156 BOOST_CHECK_EQUAL(cylinderSurfaceObject->bounds().type(),
0157 SurfaceBounds::eCylinder);
0158
0159
0160 Vector2 localPosition{0., 0.};
0161 globalPosition = cylinderSurfaceObject->localToGlobal(
0162 testContext, localPosition, momentum);
0163 Vector3 expectedPosition{1, 1, 2};
0164 BOOST_CHECK_EQUAL(globalPosition, expectedPosition);
0165
0166
0167 localPosition = cylinderSurfaceObject
0168 ->globalToLocal(testContext, globalPosition, momentum)
0169 .value();
0170 Vector2 expectedLocalPosition{0., 0.};
0171 BOOST_CHECK_EQUAL(localPosition, expectedLocalPosition);
0172
0173
0174 Vector3 offSurface{100, 1, 2};
0175 BOOST_CHECK(cylinderSurfaceObject->isOnSurface(
0176 testContext, globalPosition, momentum, BoundaryCheck(true)));
0177 BOOST_CHECK(!cylinderSurfaceObject->isOnSurface(
0178 testContext, offSurface, momentum, BoundaryCheck(true)));
0179
0180
0181 Vector3 direction{-1., 0, 0};
0182 auto sfIntersection = cylinderSurfaceObject->intersect(
0183 testContext, offSurface, direction, BoundaryCheck(false));
0184 Intersection3D expectedIntersect{Vector3{1, 1, 2}, 99.,
0185 Intersection3D::Status::reachable};
0186 BOOST_CHECK(sfIntersection[0]);
0187 CHECK_CLOSE_ABS(sfIntersection[0].position(), expectedIntersect.position(),
0188 1e-9);
0189 CHECK_CLOSE_ABS(sfIntersection[0].pathLength(),
0190 expectedIntersect.pathLength(), 1e-9);
0191
0192 BOOST_CHECK(sfIntersection[1]);
0193
0194 double pn = sfIntersection[0].pathLength();
0195 double pa = sfIntersection[1].pathLength();
0196 BOOST_CHECK_LT(std::abs(pn), std::abs(pa));
0197 BOOST_CHECK_EQUAL(sfIntersection.object(), cylinderSurfaceObject.get());
0198
0199
0200
0201 CHECK_CLOSE_REL(cylinderSurfaceObject->pathCorrection(testContext, offSurface,
0202 momentum.normalized()),
0203 std::sqrt(3.), 0.01);
0204
0205
0206 BOOST_CHECK_EQUAL(cylinderSurfaceObject->name(),
0207 std::string("Acts::CylinderSurface"));
0208
0209
0210 boost::test_tools::output_test_stream dumpOuput;
0211 cylinderSurfaceObject->toStream(testContext, dumpOuput);
0212 BOOST_CHECK(
0213 dumpOuput.is_equal("Acts::CylinderSurface\n\
0214 Center position (x, y, z) = (0.0000, 1.0000, 2.0000)\n\
0215 Rotation: colX = (1.000000, 0.000000, 0.000000)\n\
0216 colY = (0.000000, 1.000000, 0.000000)\n\
0217 colZ = (0.000000, 0.000000, 1.000000)\n\
0218 Bounds : Acts::CylinderBounds: (radius, halfLengthZ, halfPhiSector, averagePhi, bevelMinZ, bevelMaxZ) = (1.0000000, 10.0000000, 3.1415927, 0.0000000, 0.0000000, 0.0000000)"));
0219 }
0220
0221 BOOST_AUTO_TEST_CASE(CylinderSurfaceEqualityOperators) {
0222 double radius(1.0), halfZ(10.);
0223 Translation3 translation{0., 1., 2.};
0224 auto pTransform = Transform3(translation);
0225 auto cylinderSurfaceObject =
0226 Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ);
0227
0228 auto cylinderSurfaceObject2 =
0229 Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ);
0230
0231
0232 BOOST_CHECK(*cylinderSurfaceObject == *cylinderSurfaceObject2);
0233
0234 BOOST_TEST_CHECKPOINT(
0235 "Create and then assign a CylinderSurface object to the existing one");
0236
0237 auto assignedCylinderSurface =
0238 Surface::makeShared<CylinderSurface>(Transform3::Identity(), 6.6, 5.4);
0239 *assignedCylinderSurface = *cylinderSurfaceObject;
0240
0241 BOOST_CHECK(*assignedCylinderSurface == *cylinderSurfaceObject);
0242 }
0243
0244
0245 BOOST_AUTO_TEST_CASE(CylinderSurfaceExtent) {
0246
0247 double radius(1.0), halfZ(10.);
0248 Translation3 translation{0., 0., 2.};
0249 auto pTransform = Transform3(translation);
0250 auto cylinderSurface =
0251 Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ);
0252
0253 auto cylinderExtent =
0254 cylinderSurface->polyhedronRepresentation(testContext, 1).extent();
0255
0256 CHECK_CLOSE_ABS(-8, cylinderExtent.min(binZ), s_onSurfaceTolerance);
0257 CHECK_CLOSE_ABS(12, cylinderExtent.max(binZ), s_onSurfaceTolerance);
0258 CHECK_CLOSE_ABS(radius, cylinderExtent.min(binR), s_onSurfaceTolerance);
0259 CHECK_CLOSE_ABS(radius, cylinderExtent.max(binR), s_onSurfaceTolerance);
0260 CHECK_CLOSE_ABS(-radius, cylinderExtent.min(binX), s_onSurfaceTolerance);
0261 CHECK_CLOSE_ABS(radius, cylinderExtent.max(binX), s_onSurfaceTolerance);
0262 CHECK_CLOSE_ABS(-radius, cylinderExtent.min(binY), s_onSurfaceTolerance);
0263 CHECK_CLOSE_ABS(radius, cylinderExtent.max(binY), s_onSurfaceTolerance);
0264 }
0265
0266
0267 BOOST_AUTO_TEST_CASE(CylinderSurfaceAlignment) {
0268 double radius(1.0), halfZ(10.);
0269 Translation3 translation{0., 1., 2.};
0270 auto pTransform = Transform3(translation);
0271 auto cylinderSurfaceObject =
0272 Surface::makeShared<CylinderSurface>(pTransform, radius, halfZ);
0273
0274 const auto& rotation = pTransform.rotation();
0275
0276 const Vector3 localZAxis = rotation.col(2);
0277
0278 CHECK_CLOSE_ABS(localZAxis, Vector3(0., 0., 1.), 1e-15);
0279
0280
0281 Vector3 globalPosition{0, 2, 2};
0282
0283
0284
0285 const auto& loc3DToLocBound =
0286 cylinderSurfaceObject->localCartesianToBoundLocalDerivative(
0287 testContext, globalPosition);
0288
0289 ActsMatrix<2, 3> expLoc3DToLocBound = ActsMatrix<2, 3>::Zero();
0290 expLoc3DToLocBound << -1, 0, 0, 0, 0, 1;
0291 CHECK_CLOSE_ABS(loc3DToLocBound, expLoc3DToLocBound, 1e-10);
0292 }
0293
0294 BOOST_AUTO_TEST_CASE(CylinderSurfaceBinningPosition) {
0295 using namespace Acts::UnitLiterals;
0296 Vector3 s{5_mm, 7_mm, 10_cm};
0297 Transform3 trf;
0298 trf = Translation3(s) * AngleAxis3{0.5, Vector3::UnitZ()};
0299
0300 double r = 300;
0301 double halfZ = 330;
0302 double averagePhi = 0.1;
0303
0304 auto bounds =
0305 std::make_shared<CylinderBounds>(r, halfZ, M_PI / 8, averagePhi);
0306 auto cylinder = Acts::Surface::makeShared<CylinderSurface>(trf, bounds);
0307
0308 Vector3 exp = Vector3{r * std::cos(averagePhi), r * std::sin(averagePhi), 0};
0309 exp = trf * exp;
0310
0311 Vector3 bp = cylinder->binningPosition(testContext, binR);
0312 CHECK_CLOSE_ABS(bp, exp, 1e-10);
0313 CHECK_CLOSE_ABS(cylinder->binningPositionValue(testContext, binR),
0314 VectorHelpers::perp(exp), 1e-10);
0315
0316 bp = cylinder->binningPosition(testContext, binRPhi);
0317 CHECK_CLOSE_ABS(bp, exp, 1e-10);
0318 CHECK_CLOSE_ABS(cylinder->binningPositionValue(testContext, binRPhi),
0319 VectorHelpers::phi(exp) * VectorHelpers::perp(exp), 1e-10);
0320
0321 for (auto b : {binX, binY, binZ, binEta, binH, binMag}) {
0322 BOOST_TEST_CONTEXT("binValue: " << b) {
0323 BOOST_CHECK_EQUAL(cylinder->binningPosition(testContext, b),
0324 cylinder->center(testContext));
0325 }
0326 }
0327 }
0328
0329 BOOST_AUTO_TEST_SUITE_END()
0330
0331 }