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/Alignment.hpp"
0015 #include "Acts/Definitions/Tolerance.hpp"
0016 #include "Acts/Definitions/TrackParametrization.hpp"
0017 #include "Acts/Definitions/Units.hpp"
0018 #include "Acts/Geometry/Extent.hpp"
0019 #include "Acts/Geometry/GeometryContext.hpp"
0020 #include "Acts/Geometry/Polyhedron.hpp"
0021 #include "Acts/Surfaces/AnnulusBounds.hpp"
0022 #include "Acts/Surfaces/DiscSurface.hpp"
0023 #include "Acts/Surfaces/RadialBounds.hpp"
0024 #include "Acts/Surfaces/Surface.hpp"
0025 #include "Acts/Surfaces/SurfaceBounds.hpp"
0026 #include "Acts/Tests/CommonHelpers/DetectorElementStub.hpp"
0027 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0028 #include "Acts/Utilities/BinningType.hpp"
0029 #include "Acts/Utilities/Helpers.hpp"
0030 #include "Acts/Utilities/Intersection.hpp"
0031 #include "Acts/Utilities/Result.hpp"
0032
0033 #include <algorithm>
0034 #include <cmath>
0035 #include <initializer_list>
0036 #include <memory>
0037 #include <ostream>
0038 #include <string>
0039 #include <utility>
0040
0041 namespace Acts {
0042 class AssertionFailureException;
0043
0044 namespace Test {
0045
0046 GeometryContext tgContext = GeometryContext();
0047
0048 BOOST_AUTO_TEST_SUITE(Surfaces)
0049
0050 BOOST_AUTO_TEST_CASE(DiscSurfaceConstruction) {
0051
0052
0053 double rMin(1.0), rMax(5.0), halfPhiSector(M_PI / 8.);
0054
0055
0056 BOOST_CHECK_NO_THROW(
0057 Surface::makeShared<DiscSurface>(Transform3::Identity(), rMin, rMax));
0058
0059
0060 Translation3 translation{0., 1., 2.};
0061 auto pTransform = Transform3(translation);
0062 BOOST_CHECK_NO_THROW(
0063 Surface::makeShared<DiscSurface>(pTransform, rMin, rMax, halfPhiSector));
0064
0065
0066 auto anotherDiscSurface =
0067 Surface::makeShared<DiscSurface>(pTransform, rMin, rMax, halfPhiSector);
0068
0069
0070
0071
0072 auto copiedSurface = Surface::makeShared<DiscSurface>(*anotherDiscSurface);
0073 BOOST_TEST_MESSAGE("Copy constructed DiscSurface ok");
0074
0075
0076 BOOST_CHECK_NO_THROW(Surface::makeShared<DiscSurface>(
0077 tgContext, *anotherDiscSurface, pTransform));
0078
0079
0080 DetectorElementStub detElem;
0081 BOOST_CHECK_THROW(
0082 auto nullBounds = Surface::makeShared<DiscSurface>(nullptr, detElem),
0083 AssertionFailureException);
0084 }
0085
0086
0087 BOOST_AUTO_TEST_CASE(DiscSurfaceProperties) {
0088 Vector3 origin3D{0, 0, 0};
0089 double rMin(1.0), rMax(5.0), halfPhiSector(M_PI / 8.);
0090 auto discSurfaceObject = Surface::makeShared<DiscSurface>(
0091 Transform3::Identity(), rMin, rMax, halfPhiSector);
0092
0093
0094 BOOST_CHECK_EQUAL(discSurfaceObject->type(), Surface::Disc);
0095
0096
0097 Vector3 zAxis{0, 0, 1};
0098 BOOST_CHECK_EQUAL(discSurfaceObject->normal(tgContext), zAxis);
0099
0100
0101 Vector2 lpos(2.0, 0.05);
0102 BOOST_CHECK_EQUAL(discSurfaceObject->normal(tgContext, lpos), zAxis);
0103
0104
0105
0106
0107
0108 BOOST_CHECK_EQUAL(
0109 discSurfaceObject->binningPosition(tgContext, BinningValue::binRPhi),
0110 origin3D);
0111
0112
0113 BOOST_CHECK_EQUAL(discSurfaceObject->bounds().type(), SurfaceBounds::eDisc);
0114
0115 Vector3 ignoredMomentum{0., 0., 0.};
0116
0117 Vector3 point3DNotInSector{0.0, 1.2, 0};
0118 Vector3 point3DOnSurface{1.2, 0.0, 0};
0119 BOOST_CHECK(!discSurfaceObject->isOnSurface(tgContext, point3DNotInSector,
0120 ignoredMomentum,
0121 BoundaryCheck(true)));
0122 BOOST_CHECK(discSurfaceObject->isOnSurface(tgContext, point3DOnSurface,
0123 ignoredMomentum,
0124 BoundaryCheck(true)));
0125
0126
0127 Vector3 returnedPosition{10.9, 8.7, 6.5};
0128 Vector3 expectedPosition{1.2, 0, 0};
0129 Vector2 rPhiOnDisc{1.2, 0.0};
0130 Vector2 rPhiNotInSector{1.2, M_PI};
0131 returnedPosition =
0132 discSurfaceObject->localToGlobal(tgContext, rPhiOnDisc, ignoredMomentum);
0133 CHECK_CLOSE_ABS(returnedPosition, expectedPosition, 1e-6);
0134
0135 returnedPosition = discSurfaceObject->localToGlobal(
0136 tgContext, rPhiNotInSector, ignoredMomentum);
0137 Vector3 expectedNonPosition{-1.2, 0, 0};
0138 CHECK_CLOSE_ABS(returnedPosition, expectedNonPosition, 1e-6);
0139
0140
0141 Vector2 returnedLocalPosition{33., 44.};
0142 Vector2 expectedLocalPosition{1.2, 0.0};
0143 returnedLocalPosition =
0144 discSurfaceObject
0145 ->globalToLocal(tgContext, point3DOnSurface, ignoredMomentum)
0146 .value();
0147 CHECK_CLOSE_ABS(returnedLocalPosition, expectedLocalPosition, 1e-6);
0148
0149
0150 returnedLocalPosition =
0151 discSurfaceObject
0152 ->globalToLocal(tgContext, point3DNotInSector, ignoredMomentum)
0153 .value();
0154
0155 Vector3 pointOutsideR{0.0, 100., 0};
0156 returnedLocalPosition =
0157 discSurfaceObject
0158 ->globalToLocal(tgContext, pointOutsideR, ignoredMomentum)
0159 .value();
0160
0161
0162 Vector2 rPhi1_1{std::sqrt(2.), M_PI / 4.};
0163 Vector2 cartesian1_1{1., 1.};
0164 CHECK_CLOSE_REL(discSurfaceObject->localPolarToCartesian(rPhi1_1),
0165 cartesian1_1, 1e-6);
0166
0167
0168 CHECK_CLOSE_REL(discSurfaceObject->localCartesianToPolar(cartesian1_1),
0169 rPhi1_1, 1e-6);
0170
0171
0172 CHECK_CLOSE_REL(discSurfaceObject->localPolarToLocalCartesian(rPhi1_1),
0173 cartesian1_1, 1e-6);
0174
0175
0176 Vector3 cartesian3D1_1{1., 1., 0.};
0177 CHECK_CLOSE_ABS(
0178 discSurfaceObject->localCartesianToGlobal(tgContext, cartesian1_1),
0179 cartesian3D1_1, 1e-6);
0180
0181
0182 CHECK_CLOSE_REL(
0183 discSurfaceObject->globalToLocalCartesian(tgContext, cartesian3D1_1),
0184 cartesian1_1, 1e-6);
0185
0186
0187 double projected3DMomentum = std::sqrt(3.) * 1.e6;
0188 Vector3 momentum{projected3DMomentum, projected3DMomentum,
0189 projected3DMomentum};
0190 Vector3 ignoredPosition = discSurfaceObject->center(tgContext);
0191 CHECK_CLOSE_REL(discSurfaceObject->pathCorrection(tgContext, ignoredPosition,
0192 momentum.normalized()),
0193 std::sqrt(3), 0.01);
0194
0195
0196 Vector3 globalPosition{1.2, 0.0, -10.};
0197 Vector3 direction{0., 0., 1.};
0198 Vector3 expected{1.2, 0.0, 0.0};
0199
0200
0201
0202 auto sfIntersection = discSurfaceObject
0203 ->intersect(tgContext, globalPosition, direction,
0204 BoundaryCheck(false))
0205 .closest();
0206 Intersection3D expectedIntersect{Vector3{1.2, 0., 0.}, 10.,
0207 Intersection3D::Status::reachable};
0208 BOOST_CHECK(bool(sfIntersection));
0209 CHECK_CLOSE_ABS(sfIntersection.position(), expectedIntersect.position(),
0210 1e-9);
0211 CHECK_CLOSE_ABS(sfIntersection.pathLength(), expectedIntersect.pathLength(),
0212 1e-9);
0213 BOOST_CHECK_EQUAL(sfIntersection.object(), discSurfaceObject.get());
0214
0215
0216
0217 boost::test_tools::output_test_stream nameOuput;
0218 nameOuput << discSurfaceObject->name();
0219 BOOST_CHECK(nameOuput.is_equal("Acts::DiscSurface"));
0220 }
0221
0222
0223 BOOST_AUTO_TEST_CASE(DiscSurfaceAssignment) {
0224 Vector3 origin3D{0, 0, 0};
0225 double rMin(1.0), rMax(5.0), halfPhiSector(M_PI / 8.);
0226 auto discSurfaceObject = Surface::makeShared<DiscSurface>(
0227 Transform3::Identity(), rMin, rMax, halfPhiSector);
0228 auto assignedDisc =
0229 Surface::makeShared<DiscSurface>(Transform3::Identity(), 2.2, 4.4, 0.07);
0230
0231 BOOST_CHECK_NO_THROW(*assignedDisc = *discSurfaceObject);
0232 BOOST_CHECK((*assignedDisc) == (*discSurfaceObject));
0233 }
0234
0235
0236 BOOST_AUTO_TEST_CASE(DiscSurfaceExtent) {
0237 double rMin(1.0), rMax(5.0);
0238
0239 auto pDisc =
0240 Surface::makeShared<DiscSurface>(Transform3::Identity(), 0., rMax);
0241 auto pDiscExtent = pDisc->polyhedronRepresentation(tgContext, 1).extent();
0242
0243 CHECK_CLOSE_ABS(0., pDiscExtent.min(binZ), s_onSurfaceTolerance);
0244 CHECK_CLOSE_ABS(0., pDiscExtent.max(binZ), s_onSurfaceTolerance);
0245 CHECK_CLOSE_ABS(0., pDiscExtent.min(binR), s_onSurfaceTolerance);
0246 CHECK_CLOSE_ABS(rMax, pDiscExtent.max(binR), s_onSurfaceTolerance);
0247 CHECK_CLOSE_ABS(-rMax, pDiscExtent.min(binX), s_onSurfaceTolerance);
0248 CHECK_CLOSE_ABS(rMax, pDiscExtent.max(binX), s_onSurfaceTolerance);
0249 CHECK_CLOSE_ABS(-rMax, pDiscExtent.min(binY), s_onSurfaceTolerance);
0250 CHECK_CLOSE_ABS(rMax, pDiscExtent.max(binY), s_onSurfaceTolerance);
0251 CHECK_CLOSE_ABS(-M_PI, pDiscExtent.min(binPhi), s_onSurfaceTolerance);
0252 CHECK_CLOSE_ABS(M_PI, pDiscExtent.max(binPhi), s_onSurfaceTolerance);
0253
0254 auto pRing =
0255 Surface::makeShared<DiscSurface>(Transform3::Identity(), rMin, rMax);
0256 auto pRingExtent = pRing->polyhedronRepresentation(tgContext, 1).extent();
0257
0258 CHECK_CLOSE_ABS(0., pRingExtent.min(binZ), s_onSurfaceTolerance);
0259 CHECK_CLOSE_ABS(0., pRingExtent.max(binZ), s_onSurfaceTolerance);
0260 CHECK_CLOSE_ABS(rMin, pRingExtent.min(binR), s_onSurfaceTolerance);
0261 CHECK_CLOSE_ABS(rMax, pRingExtent.max(binR), s_onSurfaceTolerance);
0262 CHECK_CLOSE_ABS(-rMax, pRingExtent.min(binX), s_onSurfaceTolerance);
0263 CHECK_CLOSE_ABS(rMax, pRingExtent.max(binX), s_onSurfaceTolerance);
0264 CHECK_CLOSE_ABS(-rMax, pRingExtent.min(binY), s_onSurfaceTolerance);
0265 CHECK_CLOSE_ABS(rMax, pRingExtent.max(binY), s_onSurfaceTolerance);
0266 }
0267
0268
0269 BOOST_AUTO_TEST_CASE(DiscSurfaceAlignment) {
0270 Translation3 translation{0., 1., 2.};
0271 Transform3 transform(translation);
0272 double rMin(1.0), rMax(5.0), halfPhiSector(M_PI / 8.);
0273 auto discSurfaceObject =
0274 Surface::makeShared<DiscSurface>(transform, rMin, rMax, halfPhiSector);
0275
0276 const auto& rotation = transform.rotation();
0277
0278 const Vector3 localZAxis = rotation.col(2);
0279
0280 CHECK_CLOSE_ABS(localZAxis, Vector3(0., 0., 1.), 1e-15);
0281
0282
0283 Vector3 globalPosition{0, 4, 2};
0284 Vector3 momentum{0, 0, 1};
0285 Vector3 direction = momentum.normalized();
0286
0287
0288 const AlignmentToPathMatrix& alignToPath =
0289 discSurfaceObject->alignmentToPathDerivative(tgContext, globalPosition,
0290 direction);
0291
0292 AlignmentToPathMatrix expAlignToPath = AlignmentToPathMatrix::Zero();
0293 expAlignToPath << 0, 0, 1, 3, 0, 0;
0294
0295 CHECK_CLOSE_ABS(alignToPath, expAlignToPath, 1e-10);
0296
0297
0298
0299 const auto& loc3DToLocBound =
0300 discSurfaceObject->localCartesianToBoundLocalDerivative(tgContext,
0301 globalPosition);
0302
0303 ActsMatrix<2, 3> expLoc3DToLocBound = ActsMatrix<2, 3>::Zero();
0304 expLoc3DToLocBound << 0, 1, 0, -1.0 / 3, 0, 0;
0305 CHECK_CLOSE_ABS(loc3DToLocBound, expLoc3DToLocBound, 1e-10);
0306 }
0307
0308 BOOST_AUTO_TEST_CASE(DiscSurfaceBinningPosition) {
0309 using namespace Acts::UnitLiterals;
0310 Vector3 s{5_mm, 7_mm, 10_cm};
0311 Transform3 trf;
0312 trf = Translation3(s) * AngleAxis3{0.5, Vector3::UnitZ()};
0313
0314 double minR = 300;
0315 double maxR = 330;
0316
0317 {
0318
0319 auto bounds = std::make_shared<RadialBounds>(minR, maxR, M_PI / 8, 0.1);
0320 auto disc = Acts::Surface::makeShared<Acts::DiscSurface>(trf, bounds);
0321
0322 Vector3 bp = disc->binningPosition(tgContext, binR);
0323 double r = (bounds->rMax() + bounds->rMin()) / 2.0;
0324 double phi = bounds->get(RadialBounds::eAveragePhi);
0325 Vector3 exp = Vector3{r * std::cos(phi), r * std::sin(phi), 0};
0326 exp = trf * exp;
0327
0328 BOOST_CHECK_EQUAL(bp, exp);
0329 BOOST_CHECK_EQUAL(disc->binningPositionValue(tgContext, binR),
0330 VectorHelpers::perp(exp));
0331
0332 bp = disc->binningPosition(tgContext, binPhi);
0333 BOOST_CHECK_EQUAL(bp, exp);
0334 BOOST_CHECK_EQUAL(disc->binningPositionValue(tgContext, binPhi),
0335 VectorHelpers::phi(exp));
0336
0337 for (auto b : {binX, binY, binZ, binEta, binRPhi, binH, binMag}) {
0338 BOOST_TEST_CONTEXT("binValue: " << b) {
0339 BOOST_CHECK_EQUAL(disc->binningPosition(tgContext, b),
0340 disc->center(tgContext));
0341 }
0342 }
0343 }
0344
0345 {
0346
0347 double minPhiRel = -0.3;
0348 double maxPhiRel = 0.2;
0349 Vector2 origin{5_mm, 5_mm};
0350 auto bounds = std::make_shared<AnnulusBounds>(minR, maxR, minPhiRel,
0351 maxPhiRel, origin);
0352
0353 auto disc = Acts::Surface::makeShared<Acts::DiscSurface>(trf, bounds);
0354
0355 Vector3 bp = disc->binningPosition(tgContext, binR);
0356 double r = (bounds->rMax() + bounds->rMin()) / 2.0;
0357 double phi = bounds->get(AnnulusBounds::eAveragePhi);
0358 Vector3 exp = Vector3{r * std::cos(phi), r * std::sin(phi), 0};
0359 exp = trf * exp;
0360
0361 BOOST_CHECK_EQUAL(bp, exp);
0362
0363 bp = disc->binningPosition(tgContext, binPhi);
0364 BOOST_CHECK_EQUAL(bp, exp);
0365
0366 for (auto b : {binX, binY, binZ, binEta, binRPhi, binH, binMag}) {
0367 BOOST_TEST_CONTEXT("binValue: " << b) {
0368 BOOST_CHECK_EQUAL(disc->binningPosition(tgContext, b),
0369 disc->center(tgContext));
0370 }
0371 }
0372 }
0373 }
0374
0375 BOOST_AUTO_TEST_SUITE_END()
0376
0377 }
0378
0379 }