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