File indexing completed on 2025-01-18 09:12:51
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/Tolerance.hpp"
0015 #include "Acts/Definitions/TrackParametrization.hpp"
0016 #include "Acts/Definitions/Units.hpp"
0017 #include "Acts/Geometry/Extent.hpp"
0018 #include "Acts/Geometry/GeometryContext.hpp"
0019 #include "Acts/Geometry/Polyhedron.hpp"
0020 #include "Acts/Surfaces/PlaneSurface.hpp"
0021 #include "Acts/Surfaces/RectangleBounds.hpp"
0022 #include "Acts/Surfaces/Surface.hpp"
0023 #include "Acts/Surfaces/SurfaceBounds.hpp"
0024 #include "Acts/Surfaces/TrapezoidBounds.hpp"
0025 #include "Acts/Tests/CommonHelpers/DetectorElementStub.hpp"
0026 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0027 #include "Acts/Utilities/BinningType.hpp"
0028 #include "Acts/Utilities/Intersection.hpp"
0029 #include "Acts/Utilities/Result.hpp"
0030 #include "Acts/Utilities/ThrowAssert.hpp"
0031
0032 #include <cmath>
0033 #include <memory>
0034 #include <numbers>
0035 #include <string>
0036
0037 using namespace Acts::UnitLiterals;
0038
0039 namespace Acts::Test {
0040
0041
0042 GeometryContext tgContext = GeometryContext();
0043
0044 BOOST_AUTO_TEST_SUITE(PlaneSurfaces)
0045
0046 BOOST_AUTO_TEST_CASE(PlaneSurfaceConstruction) {
0047
0048
0049
0050
0051 auto rBounds = std::make_shared<const RectangleBounds>(3., 4.);
0052
0053 Translation3 translation{0., 1., 2.};
0054 auto pTransform = Transform3(translation);
0055
0056
0057 BOOST_CHECK_EQUAL(
0058 Surface::makeShared<PlaneSurface>(pTransform, rBounds)->type(),
0059 Surface::Plane);
0060
0061
0062 auto planeSurfaceObject =
0063 Surface::makeShared<PlaneSurface>(pTransform, rBounds);
0064 auto copiedPlaneSurface =
0065 Surface::makeShared<PlaneSurface>(*planeSurfaceObject);
0066 BOOST_CHECK_EQUAL(copiedPlaneSurface->type(), Surface::Plane);
0067 BOOST_CHECK(*copiedPlaneSurface == *planeSurfaceObject);
0068
0069
0070 auto copiedTransformedPlaneSurface = Surface::makeShared<PlaneSurface>(
0071 tgContext, *planeSurfaceObject, pTransform);
0072 BOOST_CHECK_EQUAL(copiedTransformedPlaneSurface->type(), Surface::Plane);
0073
0074
0075 DetectorElementStub detElem;
0076 BOOST_CHECK_THROW(
0077 auto nullBounds = Surface::makeShared<PlaneSurface>(nullptr, detElem),
0078 AssertionFailureException);
0079 }
0080
0081
0082 BOOST_AUTO_TEST_CASE(PlaneSurfaceProperties) {
0083
0084 auto rBounds = std::make_shared<const RectangleBounds>(3., 4.);
0085
0086
0087 Translation3 translation{0., 1., 2.};
0088 auto pTransform = Transform3(translation);
0089 auto planeSurfaceObject =
0090 Surface::makeShared<PlaneSurface>(pTransform, rBounds);
0091
0092 Translation3 translation2{0., 2., 4.};
0093 auto pTransform2 = Transform3(translation2);
0094 auto planeSurfaceObject2 =
0095 Surface::makeShared<PlaneSurface>(pTransform2, rBounds);
0096
0097
0098 BOOST_CHECK_EQUAL(planeSurfaceObject->type(), Surface::Plane);
0099
0100
0101 Vector3 referencePosition{0., 1., 2.};
0102 BOOST_CHECK_EQUAL(
0103 planeSurfaceObject->referencePosition(tgContext, AxisDirection::AxisX),
0104 referencePosition);
0105
0106
0107 Vector3 arbitraryGlobalPosition{2., 2., 2.};
0108 Vector3 momentum{1.e6, 1.e6, 1.e6};
0109 RotationMatrix3 expectedFrame;
0110 expectedFrame << 1., 0., 0., 0., 1., 0., 0., 0., 1.;
0111
0112 CHECK_CLOSE_OR_SMALL(planeSurfaceObject->referenceFrame(
0113 tgContext, arbitraryGlobalPosition, momentum),
0114 expectedFrame, 1e-6, 1e-9);
0115
0116
0117 Vector3 normal3D(0., 0., 1.);
0118 BOOST_CHECK_EQUAL(planeSurfaceObject->normal(tgContext), normal3D);
0119
0120
0121 BOOST_CHECK_EQUAL(planeSurfaceObject->bounds().type(),
0122 SurfaceBounds::eRectangle);
0123
0124
0125 Vector2 localPosition{1.5, 1.7};
0126 Vector3 globalPosition =
0127 planeSurfaceObject->localToGlobal(tgContext, localPosition, momentum);
0128
0129 Vector3 expectedPosition{1.5 + translation.x(), 1.7 + translation.y(),
0130 translation.z()};
0131
0132 CHECK_CLOSE_REL(globalPosition, expectedPosition, 1e-2);
0133
0134
0135 localPosition =
0136 planeSurfaceObject->globalToLocal(tgContext, globalPosition, momentum)
0137 .value();
0138 Vector2 expectedLocalPosition{1.5, 1.7};
0139
0140 CHECK_CLOSE_REL(localPosition, expectedLocalPosition, 1e-2);
0141
0142 Vector3 globalPositionOff =
0143 globalPosition +
0144 planeSurfaceObject->normal(tgContext, localPosition) * 0.1;
0145
0146 BOOST_CHECK(
0147 planeSurfaceObject->globalToLocal(tgContext, globalPositionOff, momentum)
0148 .error());
0149 BOOST_CHECK(planeSurfaceObject
0150 ->globalToLocal(tgContext, globalPositionOff, momentum, 0.05)
0151 .error());
0152 BOOST_CHECK(planeSurfaceObject
0153 ->globalToLocal(tgContext, globalPositionOff, momentum, 0.2)
0154 .ok());
0155
0156
0157 Vector3 offSurface{0, 1, -2.};
0158 BOOST_CHECK(planeSurfaceObject->isOnSurface(
0159 tgContext, globalPosition, momentum, BoundaryTolerance::None()));
0160 BOOST_CHECK(planeSurfaceObject->isOnSurface(tgContext, globalPosition,
0161 BoundaryTolerance::None()));
0162 BOOST_CHECK(!planeSurfaceObject->isOnSurface(tgContext, offSurface, momentum,
0163 BoundaryTolerance::None()));
0164 BOOST_CHECK(!planeSurfaceObject->isOnSurface(tgContext, offSurface,
0165 BoundaryTolerance::None()));
0166
0167
0168 Vector3 direction{0., 0., 1.};
0169 auto sfIntersection = planeSurfaceObject
0170 ->intersect(tgContext, offSurface, direction,
0171 BoundaryTolerance::None())
0172 .closest();
0173 Intersection3D expectedIntersect{Vector3{0, 1, 2}, 4.,
0174 IntersectionStatus::reachable};
0175 BOOST_CHECK(sfIntersection.isValid());
0176 BOOST_CHECK_EQUAL(sfIntersection.position(), expectedIntersect.position());
0177 BOOST_CHECK_EQUAL(sfIntersection.pathLength(),
0178 expectedIntersect.pathLength());
0179 BOOST_CHECK_EQUAL(sfIntersection.object(), planeSurfaceObject.get());
0180
0181
0182 CHECK_CLOSE_REL(planeSurfaceObject->pathCorrection(tgContext, offSurface,
0183 momentum.normalized()),
0184 std::numbers::sqrt3, 0.01);
0185
0186
0187 BOOST_CHECK_EQUAL(planeSurfaceObject->name(),
0188 std::string("Acts::PlaneSurface"));
0189
0190
0191 boost::test_tools::output_test_stream dumpOutput;
0192 dumpOutput << planeSurfaceObject->toStream(tgContext);
0193 BOOST_CHECK(dumpOutput.is_equal(
0194 "Acts::PlaneSurface\n"
0195 " Center position (x, y, z) = (0.0000, 1.0000, 2.0000)\n"
0196 " Rotation: colX = (1.000000, 0.000000, 0.000000)\n"
0197 " colY = (0.000000, 1.000000, 0.000000)\n"
0198 " colZ = (0.000000, 0.000000, 1.000000)\n"
0199 " Bounds : Acts::RectangleBounds: (hlX, hlY) = (3.0000000, "
0200 "4.0000000)\n"
0201 "(lower left, upper right):\n"
0202 "-3.0000000 -4.0000000\n"
0203 "3.0000000 4.0000000"));
0204 }
0205
0206 BOOST_AUTO_TEST_CASE(PlaneSurfaceEqualityOperators) {
0207
0208 auto rBounds = std::make_shared<const RectangleBounds>(3., 4.);
0209 Translation3 translation{0., 1., 2.};
0210 auto pTransform = Transform3(translation);
0211 auto planeSurfaceObject =
0212 Surface::makeShared<PlaneSurface>(pTransform, rBounds);
0213 auto planeSurfaceObject2 =
0214 Surface::makeShared<PlaneSurface>(pTransform, rBounds);
0215
0216
0217 BOOST_CHECK(*planeSurfaceObject == *planeSurfaceObject2);
0218
0219 BOOST_TEST_CHECKPOINT(
0220 "Create and then assign a PlaneSurface object to the existing one");
0221
0222
0223 auto assignedPlaneSurface =
0224 Surface::makeShared<PlaneSurface>(Transform3::Identity(), nullptr);
0225 *assignedPlaneSurface = *planeSurfaceObject;
0226
0227
0228 BOOST_CHECK(*assignedPlaneSurface == *planeSurfaceObject);
0229 }
0230
0231
0232 BOOST_AUTO_TEST_CASE(PlaneSurfaceExtent) {
0233
0234 static const Transform3 planeZX =
0235 AngleAxis3(-std::numbers::pi / 2., Vector3::UnitX()) *
0236 AngleAxis3(-std::numbers::pi / 2., Vector3::UnitZ()) *
0237 Transform3::Identity();
0238
0239 double rHx = 2.;
0240 double rHy = 4.;
0241 double yPs = 3.;
0242 auto rBounds = std::make_shared<RectangleBounds>(rHx, rHy);
0243
0244 auto plane = Surface::makeShared<PlaneSurface>(
0245 Transform3(Translation3(Vector3(0., yPs, 0.)) * planeZX), rBounds);
0246
0247 auto planeExtent = plane->polyhedronRepresentation(tgContext, 1).extent();
0248
0249 CHECK_CLOSE_ABS(planeExtent.min(AxisDirection::AxisZ), -rHx,
0250 s_onSurfaceTolerance);
0251 CHECK_CLOSE_ABS(planeExtent.max(AxisDirection::AxisZ), rHx,
0252 s_onSurfaceTolerance);
0253 CHECK_CLOSE_ABS(planeExtent.min(AxisDirection::AxisX), -rHy,
0254 s_onSurfaceTolerance);
0255 CHECK_CLOSE_ABS(planeExtent.max(AxisDirection::AxisX), rHy,
0256 s_onSurfaceTolerance);
0257 CHECK_CLOSE_ABS(planeExtent.min(AxisDirection::AxisY), yPs,
0258 s_onSurfaceTolerance);
0259 CHECK_CLOSE_ABS(planeExtent.max(AxisDirection::AxisY), yPs,
0260 s_onSurfaceTolerance);
0261 CHECK_CLOSE_ABS(planeExtent.min(AxisDirection::AxisR), yPs,
0262 s_onSurfaceTolerance);
0263 CHECK_CLOSE_ABS(planeExtent.max(AxisDirection::AxisR), std::hypot(yPs, rHy),
0264 s_onSurfaceTolerance);
0265
0266
0267 double alpha = 0.123;
0268 auto planeRot = Surface::makeShared<PlaneSurface>(
0269 Transform3(Translation3(Vector3(0., yPs, 0.)) *
0270 AngleAxis3(alpha, Vector3(0., 0., 1.)) * planeZX),
0271 rBounds);
0272
0273 auto planeExtentRot =
0274 planeRot->polyhedronRepresentation(tgContext, 1).extent();
0275 CHECK_CLOSE_ABS(planeExtentRot.min(AxisDirection::AxisZ), -rHx,
0276 s_onSurfaceTolerance);
0277 CHECK_CLOSE_ABS(planeExtentRot.max(AxisDirection::AxisZ), rHx,
0278 s_onSurfaceTolerance);
0279 CHECK_CLOSE_ABS(planeExtentRot.min(AxisDirection::AxisX),
0280 -rHy * std::cos(alpha), s_onSurfaceTolerance);
0281 CHECK_CLOSE_ABS(planeExtentRot.max(AxisDirection::AxisX),
0282 rHy * std::cos(alpha), s_onSurfaceTolerance);
0283 CHECK_CLOSE_ABS(planeExtentRot.min(AxisDirection::AxisY),
0284 yPs - rHy * std::sin(alpha), s_onSurfaceTolerance);
0285 CHECK_CLOSE_ABS(planeExtentRot.max(AxisDirection::AxisY),
0286 yPs + rHy * std::sin(alpha), s_onSurfaceTolerance);
0287 CHECK_CLOSE_ABS(planeExtentRot.min(AxisDirection::AxisR),
0288 yPs * std::cos(alpha), s_onSurfaceTolerance);
0289 }
0290
0291 BOOST_AUTO_TEST_CASE(RotatedTrapezoid) {
0292 const double shortHalfX = 100.;
0293 const double longHalfX = 200.;
0294 const double halfY = 300.;
0295 const double rotAngle = 45._degree;
0296
0297 Vector2 edgePoint{longHalfX - 10., halfY};
0298
0299 std::shared_ptr<TrapezoidBounds> bounds =
0300 std::make_shared<TrapezoidBounds>(shortHalfX, longHalfX, halfY);
0301
0302 BOOST_CHECK(bounds->inside(edgePoint, BoundaryTolerance::None()));
0303 BOOST_CHECK(!bounds->inside(Eigen::Rotation2D(-rotAngle) * edgePoint,
0304 BoundaryTolerance::None()));
0305
0306 std::shared_ptr<TrapezoidBounds> rotatedBounds =
0307 std::make_shared<TrapezoidBounds>(shortHalfX, longHalfX, halfY, rotAngle);
0308
0309 BOOST_CHECK(!rotatedBounds->inside(edgePoint, BoundaryTolerance::None()));
0310 BOOST_CHECK(rotatedBounds->inside(Eigen::Rotation2D(-rotAngle) * edgePoint,
0311 BoundaryTolerance::None()));
0312 }
0313
0314
0315 BOOST_AUTO_TEST_CASE(PlaneSurfaceAlignment) {
0316
0317 auto rBounds = std::make_shared<const RectangleBounds>(3., 4.);
0318
0319 Translation3 translation{0., 1., 2.};
0320 const double rotationAngle = std::numbers::pi / 2.;
0321 AngleAxis3 rotation(rotationAngle, Vector3::UnitY());
0322 RotationMatrix3 rotationMat = rotation.toRotationMatrix();
0323
0324 auto pTransform = Transform3{translation * rotationMat};
0325 auto planeSurfaceObject =
0326 Surface::makeShared<PlaneSurface>(pTransform, rBounds);
0327
0328
0329 const Vector3 localZAxis = rotationMat.col(2);
0330
0331 CHECK_CLOSE_ABS(localZAxis, Vector3(1., 0., 0.), 1e-15);
0332
0333
0334 Vector2 localPosition{1, 2};
0335 Vector3 momentum{1, 0, 0};
0336 Vector3 direction = momentum.normalized();
0337
0338 Vector3 globalPosition =
0339 planeSurfaceObject->localToGlobal(tgContext, localPosition, momentum);
0340
0341
0342 const AlignmentToPathMatrix& alignToPath =
0343 planeSurfaceObject->alignmentToPathDerivative(tgContext, globalPosition,
0344 direction);
0345
0346 AlignmentToPathMatrix expAlignToPath = AlignmentToPathMatrix::Zero();
0347 expAlignToPath << 1, 0, 0, 2, -1, 0;
0348
0349
0350 CHECK_CLOSE_ABS(alignToPath, expAlignToPath, 1e-10);
0351
0352
0353
0354 const auto& loc3DToLocBound =
0355 planeSurfaceObject->localCartesianToBoundLocalDerivative(tgContext,
0356 globalPosition);
0357
0358 CHECK_CLOSE_ABS(loc3DToLocBound, (ActsMatrix<2, 3>::Identity()), 1e-10);
0359
0360
0361
0362 FreeVector derivatives = FreeVector::Zero();
0363 derivatives.head<3>() = direction;
0364 const AlignmentToBoundMatrix& alignToBound =
0365 planeSurfaceObject->alignmentToBoundDerivative(tgContext, globalPosition,
0366 direction, derivatives);
0367 const AlignmentToPathMatrix alignToloc0 =
0368 alignToBound.block<1, 6>(eBoundLoc0, eAlignmentCenter0);
0369 const AlignmentToPathMatrix alignToloc1 =
0370 alignToBound.block<1, 6>(eBoundLoc1, eAlignmentCenter0);
0371
0372 AlignmentToPathMatrix expAlignToloc0;
0373 expAlignToloc0 << 0, 0, 1, 0, 0, 2;
0374 AlignmentToPathMatrix expAlignToloc1;
0375 expAlignToloc1 << 0, -1, 0, 0, 0, -1;
0376
0377 CHECK_CLOSE_ABS(alignToloc0, expAlignToloc0, 1e-10);
0378 CHECK_CLOSE_ABS(alignToloc1, expAlignToloc1, 1e-10);
0379 }
0380
0381 BOOST_AUTO_TEST_SUITE_END()
0382
0383 }