File indexing completed on 2025-07-12 07:53:20
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/tools/output_test_stream.hpp>
0010 #include <boost/test/unit_test.hpp>
0011
0012 #include "Acts/Definitions/Algebra.hpp"
0013 #include "Acts/Definitions/Alignment.hpp"
0014 #include "Acts/Definitions/TrackParametrization.hpp"
0015 #include "Acts/EventData/ParticleHypothesis.hpp"
0016 #include "Acts/EventData/TrackParameters.hpp"
0017 #include "Acts/EventData/detail/GenerateParameters.hpp"
0018 #include "Acts/Geometry/GeometryContext.hpp"
0019 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
0020 #include "Acts/Propagator/Propagator.hpp"
0021 #include "Acts/Propagator/StraightLineStepper.hpp"
0022 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0023 #include "Acts/Surfaces/LineBounds.hpp"
0024 #include "Acts/Surfaces/Surface.hpp"
0025 #include "Acts/Tests/CommonHelpers/DetectorElementStub.hpp"
0026 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0027 #include "Acts/Tests/CommonHelpers/LineSurfaceStub.hpp"
0028 #include "Acts/Tests/CommonHelpers/PredefinedMaterials.hpp"
0029 #include "Acts/Utilities/Intersection.hpp"
0030 #include "Acts/Utilities/Result.hpp"
0031 #include "Acts/Utilities/ThrowAssert.hpp"
0032 #include "Acts/Utilities/UnitVectors.hpp"
0033 #include "Acts/Utilities/VectorHelpers.hpp"
0034
0035 #include <cmath>
0036 #include <memory>
0037 #include <numbers>
0038 #include <optional>
0039 #include <ostream>
0040 #include <tuple>
0041 #include <vector>
0042
0043 namespace Acts::Test {
0044
0045
0046 GeometryContext tgContext = GeometryContext();
0047
0048 BOOST_AUTO_TEST_SUITE(Surfaces)
0049
0050
0051 BOOST_AUTO_TEST_CASE(LineSurface_Constructors_test) {
0052
0053
0054
0055 Translation3 translation{0., 1., 2.};
0056 Transform3 transform(translation);
0057 auto pTransform = Transform3(translation);
0058 const double radius = 2.;
0059 const double halfZ = 20.;
0060 BOOST_CHECK(LineSurfaceStub(pTransform, radius, halfZ).constructedOk());
0061
0062
0063 BOOST_CHECK(LineSurfaceStub(pTransform).constructedOk());
0064
0065
0066 auto pLineBounds = std::make_shared<const LineBounds>(2., 10.);
0067 BOOST_CHECK(LineSurfaceStub(pTransform, pLineBounds).constructedOk());
0068
0069
0070 auto pMaterial =
0071 std::make_shared<const HomogeneousSurfaceMaterial>(makePercentSlab());
0072 DetectorElementStub detElement{pTransform, pLineBounds, 0.2, pMaterial};
0073 BOOST_CHECK(LineSurfaceStub(pLineBounds, detElement).constructedOk());
0074 LineSurfaceStub lineToCopy(pTransform, 2., 20.);
0075
0076
0077 BOOST_CHECK(LineSurfaceStub(lineToCopy).constructedOk());
0078
0079
0080 BOOST_CHECK(
0081 LineSurfaceStub(tgContext, lineToCopy, transform).constructedOk());
0082
0083
0084 DetectorElementStub detElem;
0085 BOOST_CHECK_THROW(LineSurfaceStub nullBounds(nullptr, detElem),
0086 AssertionFailureException);
0087
0088 BOOST_TEST_MESSAGE(
0089 "All LineSurface constructors are callable without problem");
0090 }
0091
0092
0093 BOOST_AUTO_TEST_CASE(LineSurface_allNamedMethods_test) {
0094
0095 Translation3 translation{0., 1., 2.};
0096 Transform3 transform(translation);
0097 LineSurfaceStub line(transform, 2., 20.);
0098 Vector3 referencePosition{0., 1., 2.};
0099 CHECK_CLOSE_ABS(referencePosition,
0100 line.referencePosition(tgContext, AxisDirection::AxisX),
0101 1e-6);
0102
0103
0104 auto pLineBounds = std::make_shared<const LineBounds>(2., 10.);
0105 LineSurfaceStub boundedLine(transform, pLineBounds);
0106 const LineBounds& bounds =
0107 dynamic_cast<const LineBounds&>(boundedLine.bounds());
0108 BOOST_CHECK_EQUAL(bounds, LineBounds(2., 10.));
0109
0110
0111 Vector3 gpos{0., 1., 0.};
0112 const Vector3 mom{20., 0., 0.};
0113 Vector2 localPosition =
0114 line.globalToLocal(tgContext, gpos, mom.normalized()).value();
0115 const Vector2 expectedResult{0, -2};
0116 CHECK_CLOSE_ABS(expectedResult, localPosition, 1e-6);
0117
0118
0119 {
0120 const Vector3 direction{0., 1., 2.};
0121 auto sfIntersection =
0122 line.intersect(tgContext, {0., 0., 0.}, direction.normalized(),
0123 BoundaryTolerance::Infinite())
0124 .closest();
0125 BOOST_CHECK(sfIntersection.isValid());
0126 Vector3 expectedIntersection(0, 1., 2.);
0127 CHECK_CLOSE_ABS(sfIntersection.position(), expectedIntersection,
0128 1e-6);
0129 BOOST_CHECK_EQUAL(sfIntersection.object(), &line);
0130 }
0131
0132
0133 const Vector3 insidePosition{0., 2.5, 0.};
0134 BOOST_CHECK(line.isOnSurface(
0135 tgContext, insidePosition, mom,
0136 BoundaryTolerance::Infinite()));
0137 const Vector3 outsidePosition{100., 100., 200.};
0138 BOOST_CHECK(!line.isOnSurface(tgContext, outsidePosition, mom,
0139 BoundaryTolerance::None()));
0140
0141
0142 Vector3 returnedGlobalPosition{0., 0., 0.};
0143
0144 const Vector3 momentum{300., 200., 0.};
0145 returnedGlobalPosition =
0146 line.localToGlobal(tgContext, localPosition, momentum.normalized());
0147 const Vector3 expectedGlobalPosition{0, 1, 0};
0148 CHECK_CLOSE_ABS(returnedGlobalPosition, expectedGlobalPosition, 1e-6);
0149
0150
0151 Vector3 globalPosition{0., 0., 0.};
0152 auto returnedRotationMatrix =
0153 line.referenceFrame(tgContext, globalPosition, momentum.normalized());
0154 double v0 = std::cos(std::atan(2. / 3.));
0155 double v1 = std::sin(std::atan(2. / 3.));
0156 RotationMatrix3 expectedRotationMatrix;
0157 expectedRotationMatrix << -v1, 0., v0, v0, 0., v1, 0., 1., -0.;
0158 CHECK_CLOSE_OR_SMALL(returnedRotationMatrix, expectedRotationMatrix, 1e-6,
0159 1e-9);
0160
0161
0162 boost::test_tools::output_test_stream output;
0163 output << line.name();
0164 BOOST_CHECK(output.is_equal("Acts::LineSurface"));
0165
0166
0167
0168 Vector3 position{5, 5, 5};
0169 {
0170 Vector3 direction{1, 0, 0};
0171 CHECK_CLOSE_ABS(line.normal(tgContext, position, direction), direction,
0172 1e-6);
0173 }
0174 {
0175 Vector3 direction = Vector3{1, 0, 0.1}.normalized();
0176 CHECK_CLOSE_ABS(line.normal(tgContext, position, direction),
0177 Vector3::UnitX(), 1e-6);
0178 }
0179 {
0180 Vector3 direction{-1, 0, 0};
0181 CHECK_CLOSE_ABS(line.normal(tgContext, position, direction), direction,
0182 1e-6);
0183 }
0184 {
0185 Vector3 direction{0, 1, 0};
0186 CHECK_CLOSE_ABS(line.normal(tgContext, position, direction), direction,
0187 1e-6);
0188 }
0189
0190
0191 Vector3 any3DVector = Vector3::Random();
0192 CHECK_CLOSE_REL(line.pathCorrection(tgContext, any3DVector, any3DVector), 1.,
0193 1e-6);
0194 }
0195
0196
0197 BOOST_AUTO_TEST_CASE(LineSurface_assignment_test) {
0198 Translation3 translation{0., 1., 2.};
0199 Transform3 transform(translation);
0200 LineSurfaceStub originalLine(transform, 2., 20.);
0201 LineSurfaceStub assignedLine(transform, 1., 1.);
0202 BOOST_CHECK(assignedLine != originalLine);
0203 assignedLine = originalLine;
0204 BOOST_CHECK(assignedLine == originalLine);
0205 }
0206
0207
0208 BOOST_AUTO_TEST_CASE(LineSurfaceAlignment) {
0209 Translation3 translation{0., 1., 2.};
0210 Transform3 transform(translation);
0211 LineSurfaceStub line(transform, 2., 20.);
0212
0213 const auto& rotation = transform.rotation();
0214
0215 const Vector3 localZAxis = rotation.col(2);
0216
0217 CHECK_CLOSE_ABS(localZAxis, Vector3(0., 0., 1.), 1e-15);
0218
0219
0220 Vector3 globalPosition{1, 2, 4};
0221 Vector3 momentum{-1, 1, 1};
0222 Vector3 direction = momentum.normalized();
0223
0224
0225 const AlignmentToPathMatrix& alignToPath =
0226 line.alignmentToPathDerivative(tgContext, globalPosition, direction);
0227
0228 AlignmentToPathMatrix expAlignToPath = AlignmentToPathMatrix::Zero();
0229 const double value = std::numbers::sqrt3 / 2;
0230 expAlignToPath << -value, value, 0, -3 * value, -value, 0;
0231
0232 CHECK_CLOSE_ABS(alignToPath, expAlignToPath, 1e-10);
0233
0234
0235
0236 const auto& loc3DToLocBound =
0237 line.localCartesianToBoundLocalDerivative(tgContext, globalPosition);
0238
0239 ActsMatrix<2, 3> expLoc3DToLocBound = ActsMatrix<2, 3>::Zero();
0240 expLoc3DToLocBound << 1 / std::numbers::sqrt2, 1 / std::numbers::sqrt2, 0, 0,
0241 0, 1;
0242 CHECK_CLOSE_ABS(loc3DToLocBound, expLoc3DToLocBound, 1e-10);
0243 }
0244
0245 BOOST_AUTO_TEST_CASE(LineSurfaceTransformRoundTrip) {
0246 LineSurfaceStub surface(Transform3::Identity());
0247
0248 auto roundTrip = [&surface](const Vector3& pos, const Vector3& dir) {
0249 auto intersection = surface.intersect(tgContext, pos, dir).closest();
0250 Vector3 global = intersection.position();
0251 Vector2 local = *surface.globalToLocal(tgContext, global, dir);
0252 Vector3 global2 = surface.localToGlobal(tgContext, local, dir);
0253 return std::make_tuple(global, local, global2);
0254 };
0255
0256 {
0257 Vector3 pos = {-0.02801, 0.00475611, 0.285106};
0258 Vector3 dir = Vector3(-0.03951, -0.221457, -0.564298).normalized();
0259
0260 auto [global, local, global2] = roundTrip(pos, dir);
0261
0262 CHECK_CLOSE_ABS(global, global2, 1e-10);
0263 }
0264
0265 {
0266 Vector3 pos = {-64.2892, 65.2697, -0.839014};
0267 Vector3 dir = Vector3(-0.236602, -0.157616, 0.956786).normalized();
0268
0269 auto [global, local, global2] = roundTrip(pos, dir);
0270
0271 CHECK_CLOSE_ABS(global, global2, 1e-10);
0272 }
0273 }
0274
0275 BOOST_AUTO_TEST_CASE(LineSurfaceTransformRoundTripEtaStability) {
0276 LineSurfaceStub surface(Transform3::Identity());
0277
0278
0279 const std::vector<double> etas = {0, 1, 2, 3, 4, 5};
0280
0281 for (double eta : etas) {
0282 Vector3 pca = {5, 0, 0};
0283 Vector3 dir = makeDirectionFromPhiEta(std::numbers::pi / 2., eta);
0284 Vector3 pos = pca + dir;
0285
0286 auto intersection = surface.intersect(tgContext, pos, dir).closest();
0287
0288 Vector3 global = intersection.position();
0289 Vector2 local = *surface.globalToLocal(tgContext, global, dir);
0290 Vector3 global2 = surface.localToGlobal(tgContext, local, dir);
0291
0292 CHECK_CLOSE_ABS(global, global2, 1e-10);
0293 CHECK_CLOSE_ABS(pca, global2, 1e-10);
0294 }
0295 }
0296
0297 BOOST_AUTO_TEST_CASE(LineSurfaceIntersection) {
0298 using namespace Acts::UnitLiterals;
0299
0300 double eps = 1e-10;
0301
0302 Vector3 direction = Vector3(1, 1, 100).normalized();
0303 BoundVector boundVector;
0304 boundVector << 1_cm, 1_cm, VectorHelpers::phi(direction),
0305 VectorHelpers::theta(direction), 1, 0;
0306 double pathLimit = 1_cm;
0307
0308 auto surface = std::make_shared<LineSurfaceStub>(Transform3::Identity());
0309
0310 BoundTrackParameters initialParams{surface, boundVector, std::nullopt,
0311 ParticleHypothesis::pion()};
0312
0313 using Propagator = Propagator<StraightLineStepper>;
0314 using PropagatorOptions = Propagator::Options<>;
0315
0316 Propagator propagator({});
0317
0318 BoundTrackParameters displacedParameters =
0319 BoundTrackParameters::createCurvilinear(Vector4::Zero(), Vector3::Zero(),
0320 1, std::nullopt,
0321 ParticleHypothesis::pion());
0322 {
0323 PropagatorOptions options(tgContext, {});
0324 options.direction = Acts::Direction::Backward();
0325 options.pathLimit = pathLimit;
0326
0327 auto result = propagator.propagate(initialParams, options);
0328 BOOST_CHECK(result.ok());
0329 BOOST_CHECK(result.value().endParameters);
0330
0331 displacedParameters = result.value().endParameters.value();
0332 }
0333
0334 auto intersection =
0335 surface
0336 ->intersect(tgContext, displacedParameters.position(tgContext),
0337 displacedParameters.direction())
0338 .closest();
0339 CHECK_CLOSE_ABS(intersection.pathLength(), pathLimit, eps);
0340
0341 BoundTrackParameters endParameters{surface,
0342 detail::Test::someBoundParametersA(),
0343 std::nullopt, ParticleHypothesis::pion()};
0344 {
0345 PropagatorOptions options(tgContext, {});
0346 options.direction = Acts::Direction::Forward();
0347 options.stepping.maxStepSize = 1_mm;
0348
0349 auto result = propagator.propagate(displacedParameters, *surface, options);
0350 BOOST_CHECK(result.ok());
0351 BOOST_CHECK(result.value().endParameters);
0352 CHECK_CLOSE_ABS(result.value().pathLength, pathLimit, eps);
0353 endParameters = result.value().endParameters.value();
0354 }
0355
0356 CHECK_CLOSE_ABS(initialParams.parameters(), endParameters.parameters(), eps);
0357 }
0358
0359 BOOST_AUTO_TEST_SUITE_END()
0360
0361 }