File indexing completed on 2026-01-06 09:23:50
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/tools/context.hpp>
0010 #include <boost/test/tools/old/interface.hpp>
0011 #include <boost/test/unit_test.hpp>
0012 #include <boost/test/unit_test_suite.hpp>
0013
0014 #include "Acts/Definitions/Units.hpp"
0015 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0016 #include "Acts/Geometry/CutoutCylinderVolumeBounds.hpp"
0017 #include "Acts/Geometry/CylinderPortalShell.hpp"
0018 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0019 #include "Acts/Geometry/GridPortalLink.hpp"
0020 #include "Acts/Geometry/Portal.hpp"
0021 #include "Acts/Geometry/TrackingVolume.hpp"
0022 #include "Acts/Geometry/TrivialPortalLink.hpp"
0023 #include "Acts/Surfaces/SurfaceMergingException.hpp"
0024
0025 #include <stdexcept>
0026
0027 using namespace Acts;
0028 using namespace Acts::UnitLiterals;
0029
0030 namespace ActsTests {
0031 GeometryContext gctx;
0032
0033 std::size_t getVolumeIndex() {
0034 static std::size_t i = 1;
0035 return i++;
0036 }
0037
0038 auto makeVolume(auto&&... pars) {
0039 TrackingVolume vol(Transform3::Identity(),
0040 std::make_shared<CylinderVolumeBounds>(
0041 std::forward<decltype(pars)>(pars)...));
0042 vol.setVolumeName("cyl" + std::to_string(getVolumeIndex()));
0043 return vol;
0044 };
0045
0046 auto logger = getDefaultLogger("UnitTests", Logging::VERBOSE);
0047
0048 BOOST_AUTO_TEST_SUITE(GeometrySuite)
0049
0050 BOOST_AUTO_TEST_CASE(ConstructionFromVolume) {
0051
0052
0053
0054
0055
0056
0057 auto cyl1 = makeVolume(30_mm, 40_mm, 100_mm);
0058 auto cyl2 = makeVolume(0_mm, 40_mm, 100_mm);
0059 auto cyl3 = makeVolume(30_mm, 40_mm, 100_mm, 45_degree);
0060 auto cyl4 = makeVolume(0_mm, 40_mm, 100_mm, 45_degree);
0061
0062 TrackingVolume boxVolume(
0063 Transform3::Identity(),
0064 std::make_shared<CuboidVolumeBounds>(10_mm, 10_mm, 10_mm));
0065
0066 BOOST_CHECK_THROW(SingleCylinderPortalShell{boxVolume},
0067 std::invalid_argument);
0068
0069 SingleCylinderPortalShell shell1{cyl1};
0070 BOOST_CHECK_EQUAL(shell1.size(), 4);
0071
0072 using enum CylinderVolumeBounds::Face;
0073
0074 const auto* pDisc = shell1.portal(PositiveDisc);
0075 BOOST_REQUIRE_NE(pDisc, nullptr);
0076 BOOST_CHECK_EQUAL(
0077 pDisc
0078 ->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, -Vector3::UnitZ())
0079 .value(),
0080 &cyl1);
0081 BOOST_CHECK_EQUAL(
0082 pDisc->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, Vector3::UnitZ())
0083 .value(),
0084 nullptr);
0085
0086 const auto* nDisc = shell1.portal(NegativeDisc);
0087 BOOST_REQUIRE_NE(nDisc, nullptr);
0088 BOOST_CHECK_EQUAL(nDisc
0089 ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm},
0090 -Vector3::UnitZ())
0091 .value(),
0092 nullptr);
0093 BOOST_CHECK_EQUAL(
0094 nDisc
0095 ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm}, Vector3::UnitZ())
0096 .value(),
0097 &cyl1);
0098
0099 const auto* oCyl = shell1.portal(OuterCylinder);
0100 BOOST_REQUIRE_NE(oCyl, nullptr);
0101 BOOST_CHECK_EQUAL(
0102 oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, Vector3::UnitX())
0103 .value(),
0104 nullptr);
0105 BOOST_CHECK_EQUAL(
0106 oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, -Vector3::UnitX())
0107 .value(),
0108 &cyl1);
0109
0110 const auto* iCyl = shell1.portal(InnerCylinder);
0111 BOOST_REQUIRE_NE(iCyl, nullptr);
0112 BOOST_CHECK_EQUAL(
0113 iCyl->resolveVolume(gctx, Vector3{30_mm, 0_mm, 10_mm}, Vector3::UnitX())
0114 .value(),
0115 &cyl1);
0116 BOOST_CHECK_EQUAL(
0117 iCyl->resolveVolume(gctx, Vector3{30_mm, 0_mm, 10_mm}, -Vector3::UnitX())
0118 .value(),
0119 nullptr);
0120
0121 SingleCylinderPortalShell shell2{cyl2};
0122 BOOST_CHECK_EQUAL(shell2.size(), 3);
0123
0124 pDisc = shell2.portal(PositiveDisc);
0125 BOOST_REQUIRE_NE(pDisc, nullptr);
0126 BOOST_CHECK_EQUAL(
0127 pDisc
0128 ->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, -Vector3::UnitZ())
0129 .value(),
0130 &cyl2);
0131 BOOST_CHECK_EQUAL(
0132 pDisc->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, Vector3::UnitZ())
0133 .value(),
0134 nullptr);
0135
0136 nDisc = shell2.portal(NegativeDisc);
0137 BOOST_REQUIRE_NE(nDisc, nullptr);
0138 BOOST_CHECK_EQUAL(nDisc
0139 ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm},
0140 -Vector3::UnitZ())
0141 .value(),
0142 nullptr);
0143 BOOST_CHECK_EQUAL(
0144 nDisc
0145 ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm}, Vector3::UnitZ())
0146 .value(),
0147 &cyl2);
0148
0149 oCyl = shell2.portal(OuterCylinder);
0150 BOOST_REQUIRE_NE(oCyl, nullptr);
0151 BOOST_CHECK_EQUAL(
0152 oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, Vector3::UnitX())
0153 .value(),
0154 nullptr);
0155 BOOST_CHECK_EQUAL(
0156 oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, -Vector3::UnitX())
0157 .value(),
0158 &cyl2);
0159
0160 iCyl = shell2.portal(InnerCylinder);
0161 BOOST_CHECK_EQUAL(iCyl, nullptr);
0162
0163 SingleCylinderPortalShell shell3{cyl3};
0164 BOOST_CHECK_EQUAL(shell3.size(), 6);
0165
0166 pDisc = shell3.portal(PositiveDisc);
0167 BOOST_REQUIRE_NE(pDisc, nullptr);
0168 BOOST_CHECK_EQUAL(
0169 pDisc
0170 ->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, -Vector3::UnitZ())
0171 .value(),
0172 &cyl3);
0173 BOOST_CHECK_EQUAL(
0174 pDisc->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, Vector3::UnitZ())
0175 .value(),
0176 nullptr);
0177
0178 nDisc = shell3.portal(NegativeDisc);
0179 BOOST_REQUIRE_NE(nDisc, nullptr);
0180 BOOST_CHECK_EQUAL(nDisc
0181 ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm},
0182 -Vector3::UnitZ())
0183 .value(),
0184 nullptr);
0185 BOOST_CHECK_EQUAL(
0186 nDisc
0187 ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm}, Vector3::UnitZ())
0188 .value(),
0189 &cyl3);
0190
0191 oCyl = shell3.portal(OuterCylinder);
0192 BOOST_REQUIRE_NE(oCyl, nullptr);
0193 BOOST_CHECK_EQUAL(
0194 oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, Vector3::UnitX())
0195 .value(),
0196 nullptr);
0197 BOOST_CHECK_EQUAL(
0198 oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, -Vector3::UnitX())
0199 .value(),
0200 &cyl3);
0201
0202 iCyl = shell3.portal(InnerCylinder);
0203 BOOST_REQUIRE_NE(iCyl, nullptr);
0204 BOOST_CHECK_EQUAL(
0205 iCyl->resolveVolume(gctx, Vector3{30_mm, 0_mm, 10_mm}, Vector3::UnitX())
0206 .value(),
0207 &cyl3);
0208 BOOST_CHECK_EQUAL(
0209 iCyl->resolveVolume(gctx, Vector3{30_mm, 0_mm, 10_mm}, -Vector3::UnitX())
0210 .value(),
0211 nullptr);
0212
0213 auto anglePoint = [](double angle, double r, double z) {
0214 return Vector3{r * std::cos(angle), r * std::sin(angle), z};
0215 };
0216
0217 const auto* nPhi = shell3.portal(NegativePhiPlane);
0218 BOOST_REQUIRE_NE(nPhi, nullptr);
0219 Vector3 point = anglePoint(-45_degree, 35_mm, 10_mm);
0220 Vector3 dir = Vector3::UnitZ().cross(point).normalized();
0221 Vector3 idir = (-Vector3::UnitZ()).cross(point).normalized();
0222 BOOST_CHECK_EQUAL(nPhi->resolveVolume(gctx, point, dir).value(), nullptr);
0223 BOOST_CHECK_EQUAL(nPhi->resolveVolume(gctx, point, idir).value(), &cyl3);
0224
0225 const auto* pPhi = shell3.portal(PositivePhiPlane);
0226 BOOST_REQUIRE_NE(pPhi, nullptr);
0227 point = anglePoint(45_degree, 35_mm, 10_mm);
0228 dir = Vector3::UnitZ().cross(point).normalized();
0229 idir = (-Vector3::UnitZ()).cross(point).normalized();
0230 BOOST_CHECK_EQUAL(pPhi->resolveVolume(gctx, point, dir).value(), nullptr);
0231 BOOST_CHECK_EQUAL(pPhi->resolveVolume(gctx, point, idir).value(), &cyl3);
0232
0233 SingleCylinderPortalShell shell4{cyl4};
0234 BOOST_CHECK_EQUAL(shell4.size(), 5);
0235
0236 pDisc = shell4.portal(PositiveDisc);
0237 BOOST_REQUIRE_NE(pDisc, nullptr);
0238 BOOST_CHECK_EQUAL(
0239 pDisc
0240 ->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, -Vector3::UnitZ())
0241 .value(),
0242 &cyl4);
0243 BOOST_CHECK_EQUAL(
0244 pDisc->resolveVolume(gctx, Vector3{35_mm, 0_mm, 100_mm}, Vector3::UnitZ())
0245 .value(),
0246 nullptr);
0247
0248 nDisc = shell4.portal(NegativeDisc);
0249 BOOST_REQUIRE_NE(nDisc, nullptr);
0250 BOOST_CHECK_EQUAL(nDisc
0251 ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm},
0252 -Vector3::UnitZ())
0253 .value(),
0254 nullptr);
0255 BOOST_CHECK_EQUAL(
0256 nDisc
0257 ->resolveVolume(gctx, Vector3{35_mm, 0_mm, -100_mm}, Vector3::UnitZ())
0258 .value(),
0259 &cyl4);
0260
0261 oCyl = shell4.portal(OuterCylinder);
0262 BOOST_REQUIRE_NE(oCyl, nullptr);
0263 BOOST_CHECK_EQUAL(
0264 oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, Vector3::UnitX())
0265 .value(),
0266 nullptr);
0267 BOOST_CHECK_EQUAL(
0268 oCyl->resolveVolume(gctx, Vector3{40_mm, 0_mm, 10_mm}, -Vector3::UnitX())
0269 .value(),
0270 &cyl4);
0271
0272 iCyl = shell4.portal(InnerCylinder);
0273 BOOST_CHECK_EQUAL(iCyl, nullptr);
0274
0275 nPhi = shell4.portal(NegativePhiPlane);
0276 BOOST_REQUIRE_NE(nPhi, nullptr);
0277 point = anglePoint(-45_degree, 35_mm, 10_mm);
0278 dir = Vector3::UnitZ().cross(point).normalized();
0279 idir = (-Vector3::UnitZ()).cross(point).normalized();
0280 BOOST_CHECK_EQUAL(nPhi->resolveVolume(gctx, point, dir).value(), nullptr);
0281 BOOST_CHECK_EQUAL(nPhi->resolveVolume(gctx, point, idir).value(), &cyl4);
0282
0283 pPhi = shell4.portal(PositivePhiPlane);
0284 BOOST_REQUIRE_NE(pPhi, nullptr);
0285 point = anglePoint(45_degree, 35_mm, 10_mm);
0286 dir = Vector3::UnitZ().cross(point).normalized();
0287 idir = (-Vector3::UnitZ()).cross(point).normalized();
0288 BOOST_CHECK_EQUAL(pPhi->resolveVolume(gctx, point, dir).value(), nullptr);
0289 BOOST_CHECK_EQUAL(pPhi->resolveVolume(gctx, point, idir).value(), &cyl4);
0290 }
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302 BOOST_AUTO_TEST_CASE(PortalAssignment) {
0303 using enum CylinderVolumeBounds::Face;
0304 TrackingVolume vol(
0305 Transform3::Identity(),
0306 std::make_shared<CylinderVolumeBounds>(30_mm, 100_mm, 100_mm));
0307
0308 SingleCylinderPortalShell shell{vol};
0309
0310 const auto* iCyl = shell.portal(InnerCylinder);
0311 const auto* pDisc = shell.portal(PositiveDisc);
0312 auto* oCyl = shell.portal(OuterCylinder);
0313 auto* nDisc = shell.portal(NegativeDisc);
0314
0315
0316 BOOST_REQUIRE_NE(oCyl, nullptr);
0317 auto* oCylLink = dynamic_cast<const TrivialPortalLink*>(
0318 oCyl->getLink(Direction::OppositeNormal()));
0319 BOOST_REQUIRE_NE(oCylLink, nullptr);
0320
0321 auto grid = oCylLink->makeGrid(AxisDirection::AxisZ);
0322
0323 auto portal2 =
0324 std::make_shared<Portal>(Direction::OppositeNormal(), std::move(grid));
0325 shell.setPortal(portal2, OuterCylinder);
0326 BOOST_CHECK_EQUAL(shell.portal(OuterCylinder), portal2.get());
0327
0328
0329 BOOST_CHECK_EQUAL(shell.portal(InnerCylinder), iCyl);
0330 BOOST_CHECK_EQUAL(shell.portal(PositiveDisc), pDisc);
0331 BOOST_CHECK_EQUAL(shell.portal(NegativeDisc), nDisc);
0332
0333
0334 BOOST_REQUIRE_NE(nDisc, nullptr);
0335 auto* nDiscLink = dynamic_cast<const TrivialPortalLink*>(
0336 nDisc->getLink(Direction::AlongNormal()));
0337 BOOST_REQUIRE_NE(nDiscLink, nullptr);
0338
0339 grid = nDiscLink->makeGrid(AxisDirection::AxisR);
0340
0341 auto portal3 =
0342 std::make_shared<Portal>(Direction::AlongNormal(), std::move(grid));
0343 shell.setPortal(portal3, NegativeDisc);
0344 BOOST_CHECK_EQUAL(shell.portal(NegativeDisc), portal3.get());
0345
0346
0347 BOOST_CHECK_EQUAL(shell.portal(OuterCylinder), portal2.get());
0348 BOOST_CHECK_EQUAL(shell.portal(InnerCylinder), iCyl);
0349 BOOST_CHECK_EQUAL(shell.portal(PositiveDisc), pDisc);
0350 }
0351
0352 BOOST_AUTO_TEST_SUITE(CylinderStack)
0353 BOOST_AUTO_TEST_CASE(ZDirection) {
0354 using enum CylinderVolumeBounds::Face;
0355 BOOST_TEST_CONTEXT("rMin>0") {
0356 TrackingVolume vol1(
0357 Transform3{Translation3{Vector3::UnitZ() * -100_mm}},
0358 std::make_shared<CylinderVolumeBounds>(30_mm, 100_mm, 100_mm));
0359
0360 TrackingVolume vol2(
0361 Transform3{Translation3{Vector3::UnitZ() * 100_mm}},
0362 std::make_shared<CylinderVolumeBounds>(30_mm, 100_mm, 100_mm));
0363
0364 SingleCylinderPortalShell shell1{vol1};
0365 SingleCylinderPortalShell shell2{vol2};
0366
0367 BOOST_CHECK_NE(shell1.portal(PositiveDisc), shell2.portal(NegativeDisc));
0368
0369 CylinderStackPortalShell stack{
0370 gctx, {&shell1, &shell2}, AxisDirection::AxisZ};
0371 BOOST_CHECK_EQUAL(stack.size(), 4);
0372
0373 const auto* iCyl = stack.portal(InnerCylinder);
0374 BOOST_CHECK_EQUAL(shell1.portal(InnerCylinder), iCyl);
0375 BOOST_CHECK_EQUAL(shell2.portal(InnerCylinder), iCyl);
0376
0377 const auto* oCyl = stack.portal(OuterCylinder);
0378 BOOST_CHECK_EQUAL(shell1.portal(OuterCylinder), oCyl);
0379 BOOST_CHECK_EQUAL(shell2.portal(OuterCylinder), oCyl);
0380
0381 BOOST_CHECK_EQUAL(stack.portal(PositiveDisc), shell2.portal(PositiveDisc));
0382 BOOST_CHECK_EQUAL(stack.portal(NegativeDisc), shell1.portal(NegativeDisc));
0383
0384 BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr);
0385 BOOST_CHECK_EQUAL(stack.portalPtr(NegativePhiPlane), nullptr);
0386
0387 BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr);
0388 BOOST_CHECK_EQUAL(stack.portalPtr(PositivePhiPlane), nullptr);
0389
0390
0391 BOOST_CHECK_EQUAL(shell1.portal(PositiveDisc), shell2.portal(NegativeDisc));
0392
0393 shell1 = SingleCylinderPortalShell{vol1};
0394 shell2 = SingleCylinderPortalShell{vol2};
0395
0396 BOOST_CHECK_THROW(CylinderStackPortalShell(gctx, {&shell1, &shell2},
0397 AxisDirection::AxisR),
0398 SurfaceMergingException);
0399 }
0400
0401 BOOST_TEST_CONTEXT("rMin==0") {
0402 TrackingVolume vol1(
0403 Transform3{Translation3{Vector3::UnitZ() * -100_mm}},
0404 std::make_shared<CylinderVolumeBounds>(0_mm, 100_mm, 100_mm));
0405
0406 TrackingVolume vol2(
0407 Transform3{Translation3{Vector3::UnitZ() * 100_mm}},
0408 std::make_shared<CylinderVolumeBounds>(0_mm, 100_mm, 100_mm));
0409
0410 SingleCylinderPortalShell shell1{vol1};
0411 SingleCylinderPortalShell shell2{vol2};
0412
0413 BOOST_CHECK_EQUAL(shell1.portal(InnerCylinder), nullptr);
0414 BOOST_CHECK_EQUAL(shell2.portal(InnerCylinder), nullptr);
0415
0416 BOOST_CHECK_NE(shell1.portal(PositiveDisc), shell2.portal(NegativeDisc));
0417
0418 CylinderStackPortalShell stack{
0419 gctx, {&shell1, &shell2}, AxisDirection::AxisZ};
0420 BOOST_CHECK_EQUAL(stack.size(), 3);
0421
0422
0423 BOOST_CHECK_EQUAL(shell1.portal(PositiveDisc), shell2.portal(NegativeDisc));
0424
0425 const auto* iCyl = stack.portal(InnerCylinder);
0426 BOOST_CHECK_EQUAL(iCyl, nullptr);
0427
0428 const auto* oCyl = stack.portal(OuterCylinder);
0429 BOOST_CHECK_EQUAL(shell1.portal(OuterCylinder), oCyl);
0430 BOOST_CHECK_EQUAL(shell2.portal(OuterCylinder), oCyl);
0431
0432 BOOST_CHECK_EQUAL(stack.portal(PositiveDisc), shell2.portal(PositiveDisc));
0433 BOOST_CHECK_EQUAL(stack.portal(NegativeDisc), shell1.portal(NegativeDisc));
0434
0435 BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr);
0436 BOOST_CHECK_EQUAL(stack.portalPtr(NegativePhiPlane), nullptr);
0437
0438 BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr);
0439 BOOST_CHECK_EQUAL(stack.portalPtr(PositivePhiPlane), nullptr);
0440
0441 shell1 = SingleCylinderPortalShell{vol1};
0442 shell2 = SingleCylinderPortalShell{vol2};
0443
0444 BOOST_CHECK_THROW(CylinderStackPortalShell(gctx, {&shell1, &shell2},
0445 AxisDirection::AxisR),
0446 SurfaceMergingException);
0447 }
0448 }
0449
0450 BOOST_AUTO_TEST_CASE(RDirection) {
0451 using enum CylinderVolumeBounds::Face;
0452 BOOST_TEST_CONTEXT("rMin>0") {
0453 TrackingVolume vol1(
0454 Transform3::Identity(),
0455 std::make_shared<CylinderVolumeBounds>(30_mm, 100_mm, 100_mm));
0456
0457 TrackingVolume vol2(
0458 Transform3::Identity(),
0459 std::make_shared<CylinderVolumeBounds>(100_mm, 150_mm, 100_mm));
0460
0461 SingleCylinderPortalShell shell1{vol1};
0462 SingleCylinderPortalShell shell2{vol2};
0463
0464 BOOST_CHECK_NE(shell1.portal(OuterCylinder), shell2.portal(InnerCylinder));
0465
0466 CylinderStackPortalShell stack{
0467 gctx, {&shell1, &shell2}, AxisDirection::AxisR};
0468 BOOST_CHECK_EQUAL(stack.size(), 4);
0469
0470
0471 BOOST_CHECK_EQUAL(shell1.portal(OuterCylinder),
0472 shell2.portal(InnerCylinder));
0473
0474 const auto* nDisc = stack.portal(NegativeDisc);
0475 const auto* pDisc = stack.portal(PositiveDisc);
0476
0477 BOOST_CHECK_EQUAL(shell1.portal(NegativeDisc), nDisc);
0478 BOOST_CHECK_EQUAL(shell2.portal(NegativeDisc), nDisc);
0479 BOOST_CHECK_EQUAL(shell1.portal(PositiveDisc), pDisc);
0480 BOOST_CHECK_EQUAL(shell2.portal(PositiveDisc), pDisc);
0481
0482 BOOST_CHECK_EQUAL(stack.portal(InnerCylinder),
0483 shell1.portal(InnerCylinder));
0484 BOOST_CHECK_EQUAL(stack.portal(OuterCylinder),
0485 shell2.portal(OuterCylinder));
0486
0487 BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr);
0488 BOOST_CHECK_EQUAL(stack.portalPtr(NegativePhiPlane), nullptr);
0489
0490 BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr);
0491 BOOST_CHECK_EQUAL(stack.portalPtr(PositivePhiPlane), nullptr);
0492
0493 shell1 = SingleCylinderPortalShell{vol1};
0494 shell2 = SingleCylinderPortalShell{vol2};
0495
0496 BOOST_CHECK_THROW(CylinderStackPortalShell(gctx, {&shell1, &shell2},
0497 AxisDirection::AxisZ),
0498 SurfaceMergingException);
0499 }
0500
0501 BOOST_TEST_CONTEXT("rMin==0") {
0502 TrackingVolume vol1(
0503 Transform3::Identity(),
0504 std::make_shared<CylinderVolumeBounds>(0_mm, 100_mm, 100_mm));
0505
0506 TrackingVolume vol2(
0507 Transform3::Identity(),
0508 std::make_shared<CylinderVolumeBounds>(100_mm, 150_mm, 100_mm));
0509
0510 SingleCylinderPortalShell shell1{vol1};
0511 SingleCylinderPortalShell shell2{vol2};
0512
0513 BOOST_CHECK_EQUAL(shell1.portal(InnerCylinder), nullptr);
0514 BOOST_CHECK_NE(shell1.portal(OuterCylinder), shell2.portal(InnerCylinder));
0515
0516 CylinderStackPortalShell stack{
0517 gctx, {&shell1, &shell2}, AxisDirection::AxisR};
0518 BOOST_CHECK_EQUAL(stack.size(), 4);
0519
0520
0521 BOOST_CHECK_EQUAL(shell1.portal(OuterCylinder),
0522 shell2.portal(InnerCylinder));
0523
0524 const auto* nDisc = stack.portal(NegativeDisc);
0525 const auto* pDisc = stack.portal(PositiveDisc);
0526
0527 BOOST_CHECK_EQUAL(shell1.portal(NegativeDisc), nDisc);
0528 BOOST_CHECK_EQUAL(shell2.portal(NegativeDisc), nDisc);
0529 BOOST_CHECK_EQUAL(shell1.portal(PositiveDisc), pDisc);
0530 BOOST_CHECK_EQUAL(shell2.portal(PositiveDisc), pDisc);
0531
0532 BOOST_CHECK_EQUAL(stack.portal(InnerCylinder), nullptr);
0533 BOOST_CHECK_EQUAL(stack.portal(OuterCylinder),
0534 shell2.portal(OuterCylinder));
0535
0536 BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr);
0537 BOOST_CHECK_EQUAL(stack.portalPtr(NegativePhiPlane), nullptr);
0538
0539 BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr);
0540 BOOST_CHECK_EQUAL(stack.portalPtr(PositivePhiPlane), nullptr);
0541
0542 shell1 = SingleCylinderPortalShell{vol1};
0543 shell2 = SingleCylinderPortalShell{vol2};
0544
0545 BOOST_CHECK_THROW(CylinderStackPortalShell(gctx, {&shell1, &shell2},
0546 AxisDirection::AxisZ),
0547 std::invalid_argument);
0548 }
0549 }
0550
0551 BOOST_AUTO_TEST_CASE(NestedStacks) {
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576 Transform3 base = Transform3::Identity();
0577
0578 TrackingVolume vol1(
0579 base, std::make_shared<CylinderVolumeBounds>(23_mm, 48_mm, 200_mm),
0580 "PixelLayer0");
0581
0582 TrackingVolume gap(
0583 base, std::make_shared<CylinderVolumeBounds>(48_mm, 250_mm, 200_mm),
0584 "Gap");
0585
0586 TrackingVolume vol2(
0587 base, std::make_shared<CylinderVolumeBounds>(250_mm, 400_mm, 200_mm),
0588 "PixelLayer3");
0589
0590 TrackingVolume vol3(
0591 base * Translation3{Vector3::UnitZ() * 300_mm},
0592 std::make_shared<CylinderVolumeBounds>(23_mm, 400_mm, 100_mm),
0593 "PixelEcPos");
0594
0595 SingleCylinderPortalShell shell1{vol1};
0596 BOOST_CHECK(shell1.isValid());
0597 SingleCylinderPortalShell gapShell{gap};
0598 BOOST_CHECK(gapShell.isValid());
0599 SingleCylinderPortalShell shell2{vol2};
0600 BOOST_CHECK(shell2.isValid());
0601
0602 CylinderStackPortalShell stack{
0603 gctx, {&shell1, &gapShell, &shell2}, AxisDirection::AxisR};
0604
0605 BOOST_CHECK(stack.isValid());
0606
0607 SingleCylinderPortalShell shell3{vol3};
0608 BOOST_CHECK(shell3.isValid());
0609
0610 CylinderStackPortalShell stack2{
0611 gctx, {&stack, &shell3}, AxisDirection::AxisZ, *logger};
0612 BOOST_CHECK(stack2.isValid());
0613
0614 using enum CylinderVolumeBounds::Face;
0615
0616 auto lookup = [](auto& shell, CylinderPortalShell::Face face,
0617 Vector3 position,
0618 Vector3 direction) -> const TrackingVolume* {
0619 const auto* portal = shell.portal(face);
0620 BOOST_REQUIRE_NE(portal, nullptr);
0621 return portal->resolveVolume(gctx, position, direction).value();
0622 };
0623
0624
0625
0626 BOOST_CHECK_EQUAL(lookup(shell1, InnerCylinder, 23_mm * Vector3::UnitX(),
0627 -Vector3::UnitX()),
0628 nullptr);
0629 BOOST_CHECK_EQUAL(
0630 lookup(shell1, InnerCylinder, 23_mm * Vector3::UnitX(), Vector3::UnitX()),
0631 &vol1);
0632
0633 BOOST_CHECK_EQUAL(
0634 lookup(shell1, OuterCylinder, 48_mm * Vector3::UnitX(), Vector3::UnitX()),
0635 &gap);
0636
0637 BOOST_CHECK_EQUAL(lookup(gapShell, InnerCylinder, 48_mm * Vector3::UnitX(),
0638 -Vector3::UnitX()),
0639 &vol1);
0640
0641 BOOST_CHECK_EQUAL(lookup(gapShell, OuterCylinder, 250_mm * Vector3::UnitX(),
0642 Vector3::UnitX()),
0643 &vol2);
0644
0645 BOOST_CHECK_EQUAL(lookup(shell2, InnerCylinder, 250_mm * Vector3::UnitX(),
0646 -Vector3::UnitX()),
0647 &gap);
0648
0649 BOOST_CHECK_EQUAL(lookup(shell2, OuterCylinder, 400_mm * Vector3::UnitX(),
0650 Vector3::UnitX()),
0651 nullptr);
0652
0653 BOOST_CHECK_EQUAL(lookup(shell2, OuterCylinder, 400_mm * Vector3::UnitX(),
0654 -Vector3::UnitX()),
0655 &vol2);
0656
0657 BOOST_CHECK_EQUAL(lookup(shell2, OuterCylinder, 400_mm * Vector3::UnitX(),
0658 -Vector3::UnitX()),
0659 &vol2);
0660
0661
0662
0663 BOOST_CHECK_EQUAL(lookup(shell1, NegativeDisc, Vector3(30_mm, 0, -200_mm),
0664 -Vector3::UnitZ()),
0665 nullptr);
0666
0667 BOOST_CHECK_EQUAL(lookup(shell1, NegativeDisc, Vector3(30_mm, 0, -200_mm),
0668 Vector3::UnitZ()),
0669 &vol1);
0670
0671 BOOST_CHECK_EQUAL(lookup(gapShell, NegativeDisc, Vector3(60_mm, 0, -200_mm),
0672 -Vector3::UnitZ()),
0673 nullptr);
0674
0675 BOOST_CHECK_EQUAL(lookup(gapShell, NegativeDisc, Vector3(60_mm, 0, -200_mm),
0676 Vector3::UnitZ()),
0677 &gap);
0678
0679 BOOST_CHECK_EQUAL(lookup(shell2, NegativeDisc, Vector3(300_mm, 0, -200_mm),
0680 -Vector3::UnitZ()),
0681 nullptr);
0682
0683 BOOST_CHECK_EQUAL(lookup(shell2, NegativeDisc, Vector3(300_mm, 0, -200_mm),
0684 Vector3::UnitZ()),
0685 &vol2);
0686
0687
0688
0689 BOOST_CHECK_EQUAL(lookup(shell1, PositiveDisc, Vector3(30_mm, 0, 200_mm),
0690 -Vector3::UnitZ()),
0691 &vol1);
0692
0693 BOOST_CHECK_EQUAL(
0694 lookup(shell1, PositiveDisc, Vector3(30_mm, 0, 200_mm), Vector3::UnitZ()),
0695 &vol3);
0696
0697 BOOST_CHECK_EQUAL(lookup(gapShell, PositiveDisc, Vector3(60_mm, 0, 200_mm),
0698 -Vector3::UnitZ()),
0699 &gap);
0700
0701 BOOST_CHECK_EQUAL(lookup(gapShell, PositiveDisc, Vector3(60_mm, 0, 200_mm),
0702 Vector3::UnitZ()),
0703 &vol3);
0704
0705 BOOST_CHECK_EQUAL(lookup(shell2, PositiveDisc, Vector3(300_mm, 0, 200_mm),
0706 -Vector3::UnitZ()),
0707 &vol2);
0708
0709 BOOST_CHECK_EQUAL(lookup(shell2, PositiveDisc, Vector3(300_mm, 0, 200_mm),
0710 Vector3::UnitZ()),
0711 &vol3);
0712
0713
0714
0715 BOOST_CHECK_EQUAL(lookup(shell3, PositiveDisc, Vector3(300_mm, 0, 400_mm),
0716 -Vector3::UnitZ()),
0717 &vol3);
0718
0719 BOOST_CHECK_EQUAL(lookup(shell3, PositiveDisc, Vector3(300_mm, 0, 400_mm),
0720 Vector3::UnitZ()),
0721 nullptr);
0722 }
0723
0724 BOOST_AUTO_TEST_CASE(Fill) {
0725 auto cyl1 = makeVolume(30_mm, 40_mm, 100_mm);
0726 auto cyl2 = makeVolume(0_mm, 50_mm, 110_mm);
0727
0728 SingleCylinderPortalShell shell{cyl1};
0729
0730 using enum CylinderVolumeBounds::Face;
0731 BOOST_CHECK_EQUAL(
0732 shell.portal(OuterCylinder)->getLink(Direction::AlongNormal()), nullptr);
0733 BOOST_CHECK_EQUAL(
0734 shell.portal(InnerCylinder)->getLink(Direction::OppositeNormal()),
0735 nullptr);
0736 BOOST_CHECK_EQUAL(
0737 shell.portal(PositiveDisc)->getLink(Direction::AlongNormal()), nullptr);
0738 BOOST_CHECK_EQUAL(
0739 shell.portal(NegativeDisc)->getLink(Direction::OppositeNormal()),
0740 nullptr);
0741
0742 shell.fill(cyl2);
0743
0744 BOOST_CHECK_NE(shell.portal(OuterCylinder)->getLink(Direction::AlongNormal()),
0745 nullptr);
0746 BOOST_CHECK_NE(
0747 shell.portal(InnerCylinder)->getLink(Direction::OppositeNormal()),
0748 nullptr);
0749 BOOST_CHECK_NE(shell.portal(PositiveDisc)->getLink(Direction::AlongNormal()),
0750 nullptr);
0751 BOOST_CHECK_NE(
0752 shell.portal(NegativeDisc)->getLink(Direction::OppositeNormal()),
0753 nullptr);
0754 }
0755
0756 BOOST_AUTO_TEST_CASE(RegisterInto) {
0757 using enum CylinderVolumeBounds::Face;
0758 TrackingVolume vol1(
0759 Transform3::Identity(),
0760 std::make_shared<CylinderVolumeBounds>(0_mm, 100_mm, 100_mm));
0761
0762 SingleCylinderPortalShell shell{vol1};
0763
0764 BOOST_CHECK_EQUAL(vol1.portals().size(), 0);
0765
0766 shell.applyToVolume();
0767 BOOST_CHECK_EQUAL(vol1.portals().size(), 3);
0768 }
0769
0770 BOOST_AUTO_TEST_SUITE_END()
0771 BOOST_AUTO_TEST_SUITE_END()
0772
0773 }