File indexing completed on 2025-10-23 08:24:24
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/Geometry/Extent.hpp"
0016 #include "Acts/Geometry/GeometryContext.hpp"
0017 #include "Acts/Geometry/Polyhedron.hpp"
0018 #include "Acts/Surfaces/ConeBounds.hpp"
0019 #include "Acts/Surfaces/ConeSurface.hpp"
0020 #include "Acts/Surfaces/Surface.hpp"
0021 #include "Acts/Surfaces/SurfaceBounds.hpp"
0022 #include "Acts/Utilities/BinningType.hpp"
0023 #include "Acts/Utilities/Result.hpp"
0024 #include "Acts/Utilities/ThrowAssert.hpp"
0025 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0026
0027 #include <cmath>
0028 #include <memory>
0029 #include <numbers>
0030 #include <string>
0031
0032 using namespace Acts;
0033 namespace ActsTests {
0034
0035
0036 GeometryContext tgContext = GeometryContext();
0037
0038 BOOST_AUTO_TEST_SUITE(SurfacesSuite)
0039
0040
0041 BOOST_AUTO_TEST_CASE(ConeSurfaceConstruction) {
0042
0043
0044
0045
0046 const double alpha = std::numbers::pi / 8.;
0047 const double halfPhiSector = std::numbers::pi / 16.;
0048 const double zMin = 1.;
0049 const double zMax = 10.;
0050 const bool symmetric = false;
0051 const Translation3 translation{0., 1., 2.};
0052
0053 auto pTransform = Transform3(translation);
0054 BOOST_CHECK_EQUAL(
0055 Surface::makeShared<ConeSurface>(Transform3::Identity(), alpha, symmetric)
0056 ->type(),
0057 Surface::Cone);
0058 BOOST_CHECK_EQUAL(
0059 Surface::makeShared<ConeSurface>(pTransform, alpha, symmetric)->type(),
0060 Surface::Cone);
0061
0062
0063 BOOST_CHECK_EQUAL(Surface::makeShared<ConeSurface>(pTransform, alpha, zMin,
0064 zMax, halfPhiSector)
0065 ->type(),
0066 Surface::Cone);
0067
0068
0069 auto pConeBounds =
0070 std::make_shared<const ConeBounds>(alpha, zMin, zMax, halfPhiSector, 0.);
0071 BOOST_CHECK_EQUAL(
0072 Surface::makeShared<ConeSurface>(pTransform, pConeBounds)->type(),
0073 Surface::Cone);
0074
0075
0076 auto coneSurfaceObject =
0077 Surface::makeShared<ConeSurface>(pTransform, alpha, symmetric);
0078 auto copiedConeSurface = Surface::makeShared<ConeSurface>(*coneSurfaceObject);
0079 BOOST_CHECK_EQUAL(copiedConeSurface->type(), Surface::Cone);
0080 BOOST_CHECK(*copiedConeSurface == *coneSurfaceObject);
0081
0082
0083 auto copiedTransformedConeSurface = Surface::makeShared<ConeSurface>(
0084 tgContext, *coneSurfaceObject, pTransform);
0085 BOOST_CHECK_EQUAL(copiedTransformedConeSurface->type(), Surface::Cone);
0086
0087
0088 BOOST_CHECK_THROW(auto nullBounds = Surface::makeShared<ConeSurface>(
0089 Transform3::Identity(), nullptr),
0090 AssertionFailureException);
0091 }
0092
0093
0094 BOOST_AUTO_TEST_CASE(ConeSurfaceProperties) {
0095
0096 const double alpha = std::numbers::pi / 8.;
0097 const bool symmetric = false;
0098 const Translation3 translation{0., 1., 2.};
0099
0100 auto pTransform = Transform3(translation);
0101 auto coneSurfaceObject =
0102 Surface::makeShared<ConeSurface>(pTransform, alpha, symmetric);
0103
0104
0105 BOOST_CHECK_EQUAL(coneSurfaceObject->type(), Surface::Cone);
0106
0107
0108 Vector3 referencePosition{0., 1., 2.};
0109 CHECK_CLOSE_ABS(
0110 coneSurfaceObject->referencePosition(tgContext, AxisDirection::AxisPhi),
0111 referencePosition, 1e-6);
0112
0113
0114 Vector3 globalPosition{2., 2., 2.};
0115 Vector3 momentum{1.e6, 1.e6, 1.e6};
0116 double rootHalf = std::sqrt(0.5);
0117 RotationMatrix3 expectedFrame;
0118 expectedFrame << -rootHalf, 0., rootHalf, rootHalf, 0., rootHalf, 0., 1., 0.;
0119 CHECK_CLOSE_OR_SMALL(
0120 coneSurfaceObject->referenceFrame(tgContext, globalPosition, momentum),
0121 expectedFrame, 1e-6, 1e-9);
0122
0123
0124 Vector3 origin{0., 0., 0.};
0125 Vector3 normal3D = {0., -1., 0.};
0126 CHECK_CLOSE_ABS(coneSurfaceObject->normal(tgContext, origin), normal3D, 1e-6);
0127
0128
0129 Vector2 positionPiBy2(1., std::numbers::pi / 2.);
0130 Vector3 normalAtPiBy2{0.0312768, 0.92335, -0.382683};
0131
0132 CHECK_CLOSE_OR_SMALL(coneSurfaceObject->normal(tgContext, positionPiBy2),
0133 normalAtPiBy2, 1e-2, 1e-9);
0134
0135
0136 Vector3 symmetryAxis{0., 0., 1.};
0137 CHECK_CLOSE_ABS(coneSurfaceObject->rotSymmetryAxis(tgContext), symmetryAxis,
0138 1e-6);
0139
0140
0141 BOOST_CHECK_EQUAL(coneSurfaceObject->bounds().type(), SurfaceBounds::eCone);
0142
0143
0144 Vector2 localPosition{1., std::numbers::pi / 2.};
0145 globalPosition =
0146 coneSurfaceObject->localToGlobal(tgContext, localPosition, momentum);
0147 Vector3 expectedPosition{0.0220268, 1.65027, 3.5708};
0148
0149 CHECK_CLOSE_REL(globalPosition, expectedPosition, 1e-2);
0150
0151
0152 localPosition =
0153 coneSurfaceObject->globalToLocal(tgContext, globalPosition, momentum)
0154 .value();
0155 Vector2 expectedLocalPosition{1., std::numbers::pi / 2.};
0156
0157 CHECK_CLOSE_REL(localPosition, expectedLocalPosition, 1e-6);
0158
0159
0160 Vector3 offSurface{100, 1, 2};
0161 BOOST_CHECK(coneSurfaceObject->isOnSurface(
0162 tgContext, globalPosition, momentum, BoundaryTolerance::None()));
0163 BOOST_CHECK(!coneSurfaceObject->isOnSurface(tgContext, offSurface, momentum,
0164 BoundaryTolerance::None()));
0165
0166
0167 CHECK_CLOSE_REL(coneSurfaceObject->pathCorrection(tgContext, offSurface,
0168 momentum.normalized()),
0169 0.40218866453252877, 0.01);
0170
0171
0172 BOOST_CHECK_EQUAL(coneSurfaceObject->name(),
0173 std::string("Acts::ConeSurface"));
0174
0175
0176 boost::test_tools::output_test_stream dumpOutput;
0177 dumpOutput << coneSurfaceObject->toStream(tgContext);
0178 BOOST_CHECK(dumpOutput.is_equal(
0179 "Acts::ConeSurface\n"
0180 " Center position (x, y, z) = (0.0000, 1.0000, 2.0000)\n"
0181 " Rotation: colX = (1.000000, 0.000000, 0.000000)\n"
0182 " colY = (0.000000, 1.000000, 0.000000)\n"
0183 " colZ = (0.000000, 0.000000, 1.000000)\n"
0184 " Bounds : Acts::ConeBounds: (tanAlpha, minZ, maxZ, halfPhiSector, "
0185 "averagePhi) = (0.4142136, 0.0000000, inf, 3.1415927, 0.0000000)"
0186
0187 ));
0188 }
0189
0190 BOOST_AUTO_TEST_CASE(ConeSurfaceEqualityOperators) {
0191 const double alpha = std::numbers::pi / 8.;
0192 const bool symmetric = false;
0193 const Translation3 translation{0., 1., 2.};
0194
0195 auto pTransform = Transform3(translation);
0196 auto coneSurfaceObject =
0197 Surface::makeShared<ConeSurface>(pTransform, alpha, symmetric);
0198
0199 auto coneSurfaceObject2 =
0200 Surface::makeShared<ConeSurface>(pTransform, alpha, symmetric);
0201
0202
0203 BOOST_CHECK(*coneSurfaceObject == *coneSurfaceObject2);
0204
0205 BOOST_TEST_CHECKPOINT(
0206 "Create and then assign a ConeSurface object to the existing one");
0207
0208 auto assignedConeSurface =
0209 Surface::makeShared<ConeSurface>(Transform3::Identity(), 0.1, true);
0210 *assignedConeSurface = *coneSurfaceObject;
0211
0212 BOOST_CHECK(*assignedConeSurface == *coneSurfaceObject);
0213 }
0214
0215 BOOST_AUTO_TEST_CASE(ConeSurfaceExtent) {
0216 const double alpha = std::numbers::pi / 8.;
0217 const double halfPhiSector = std::numbers::pi / 8.;
0218 const double zMin = 0.;
0219 const double zMax = 10.;
0220 const Translation3 translation{0., 0., 0.};
0221
0222
0223 auto pTransform = Transform3(translation);
0224 auto pConeBounds = std::make_shared<const ConeBounds>(alpha, zMin, zMax);
0225 auto pCone = Surface::makeShared<ConeSurface>(pTransform, pConeBounds);
0226 auto pConeExtent = pCone->polyhedronRepresentation(tgContext, 1).extent();
0227
0228 double rMax = zMax * std::tan(alpha);
0229 CHECK_CLOSE_ABS(zMin, pConeExtent.min(AxisDirection::AxisZ),
0230 s_onSurfaceTolerance);
0231 CHECK_CLOSE_ABS(zMax, pConeExtent.max(AxisDirection::AxisZ),
0232 s_onSurfaceTolerance);
0233 CHECK_CLOSE_ABS(0., pConeExtent.min(AxisDirection::AxisR),
0234 s_onSurfaceTolerance);
0235 CHECK_CLOSE_ABS(rMax, pConeExtent.max(AxisDirection::AxisR),
0236 s_onSurfaceTolerance);
0237 CHECK_CLOSE_ABS(-rMax, pConeExtent.min(AxisDirection::AxisX),
0238 s_onSurfaceTolerance);
0239 CHECK_CLOSE_ABS(rMax, pConeExtent.max(AxisDirection::AxisX),
0240 s_onSurfaceTolerance);
0241 CHECK_CLOSE_ABS(-rMax, pConeExtent.min(AxisDirection::AxisY),
0242 s_onSurfaceTolerance);
0243 CHECK_CLOSE_ABS(rMax, pConeExtent.max(AxisDirection::AxisY),
0244 s_onSurfaceTolerance);
0245
0246
0247 pConeBounds =
0248 std::make_shared<const ConeBounds>(alpha, zMin, zMax, halfPhiSector, 0.);
0249 pCone = Surface::makeShared<ConeSurface>(pTransform, pConeBounds);
0250 pConeExtent = pCone->polyhedronRepresentation(tgContext, 1).extent();
0251
0252 CHECK_CLOSE_ABS(zMin, pConeExtent.min(AxisDirection::AxisZ),
0253 s_onSurfaceTolerance);
0254 CHECK_CLOSE_ABS(zMax, pConeExtent.max(AxisDirection::AxisZ),
0255 s_onSurfaceTolerance);
0256 CHECK_CLOSE_ABS(0., pConeExtent.min(AxisDirection::AxisR),
0257 s_onSurfaceTolerance);
0258 CHECK_CLOSE_ABS(rMax, pConeExtent.max(AxisDirection::AxisR),
0259 s_onSurfaceTolerance);
0260 }
0261
0262
0263 BOOST_AUTO_TEST_CASE(ConeSurfaceAlignment) {
0264 const double alpha = std::numbers::pi / 8.;
0265 const bool symmetric = false;
0266 const Translation3 translation{0., 1., 2.};
0267
0268 auto pTransform = Transform3(translation);
0269 auto coneSurfaceObject =
0270 Surface::makeShared<ConeSurface>(pTransform, alpha, symmetric);
0271
0272 const auto& rotation = pTransform.rotation();
0273
0274 const Vector3 localZAxis = rotation.col(2);
0275
0276 CHECK_CLOSE_ABS(localZAxis, Vector3(0., 0., 1.), 1e-15);
0277
0278
0279 Vector3 globalPosition{0, 1. + std::tan(alpha), 3};
0280
0281
0282
0283 const auto& loc3DToLocBound =
0284 coneSurfaceObject->localCartesianToBoundLocalDerivative(tgContext,
0285 globalPosition);
0286
0287 ActsMatrix<2, 3> expLoc3DToLocBound = ActsMatrix<2, 3>::Zero();
0288 expLoc3DToLocBound << -1, 0, std::numbers::pi / 2. * std::tan(alpha), 0, 0, 1;
0289 CHECK_CLOSE_ABS(loc3DToLocBound, expLoc3DToLocBound, 1e-10);
0290 }
0291
0292 BOOST_AUTO_TEST_SUITE_END()
0293 }