File indexing completed on 2026-07-16 08:08:42
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 auto gctx = GeometryContext::dangerouslyDefaultConstruct();
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).get();
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).get();
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).get();
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).get();
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).get();
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).get();
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).get();
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).get();
0161 BOOST_CHECK_EQUAL(iCyl, nullptr);
0162
0163 SingleCylinderPortalShell shell3{cyl3};
0164 BOOST_CHECK_EQUAL(shell3.size(), 6);
0165
0166 pDisc = shell3.portal(PositiveDisc).get();
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).get();
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).get();
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).get();
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).get();
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).get();
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).get();
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).get();
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).get();
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).get();
0273 BOOST_CHECK_EQUAL(iCyl, nullptr);
0274
0275 nPhi = shell4.portal(NegativePhiPlane).get();
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).get();
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);
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);
0345
0346
0347 BOOST_CHECK_EQUAL(shell.portal(OuterCylinder), portal2);
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 BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr);
0384 BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr);
0385
0386 BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr);
0387 BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr);
0388
0389
0390 BOOST_CHECK_EQUAL(shell1.portal(PositiveDisc), shell2.portal(NegativeDisc));
0391 shell1 = SingleCylinderPortalShell{vol1};
0392 shell2 = SingleCylinderPortalShell{vol2};
0393
0394 BOOST_CHECK_THROW(CylinderStackPortalShell(gctx, {&shell1, &shell2},
0395 AxisDirection::AxisR),
0396 SurfaceMergingException);
0397 }
0398
0399 BOOST_TEST_CONTEXT("rMin==0") {
0400 TrackingVolume vol1(
0401 Transform3{Translation3{Vector3::UnitZ() * -100_mm}},
0402 std::make_shared<CylinderVolumeBounds>(0_mm, 100_mm, 100_mm));
0403
0404 TrackingVolume vol2(
0405 Transform3{Translation3{Vector3::UnitZ() * 100_mm}},
0406 std::make_shared<CylinderVolumeBounds>(0_mm, 100_mm, 100_mm));
0407
0408 SingleCylinderPortalShell shell1{vol1};
0409 SingleCylinderPortalShell shell2{vol2};
0410
0411 BOOST_CHECK_EQUAL(shell1.portal(InnerCylinder), nullptr);
0412 BOOST_CHECK_EQUAL(shell2.portal(InnerCylinder), nullptr);
0413
0414 BOOST_CHECK_NE(shell1.portal(PositiveDisc), shell2.portal(NegativeDisc));
0415
0416 CylinderStackPortalShell stack{
0417 gctx, {&shell1, &shell2}, AxisDirection::AxisZ};
0418 BOOST_CHECK_EQUAL(stack.size(), 3);
0419
0420
0421 BOOST_CHECK_EQUAL(shell1.portal(PositiveDisc), shell2.portal(NegativeDisc));
0422
0423 const auto iCyl = stack.portal(InnerCylinder);
0424 BOOST_CHECK_EQUAL(iCyl, nullptr);
0425
0426 const auto oCyl = stack.portal(OuterCylinder);
0427 BOOST_CHECK_EQUAL(shell1.portal(OuterCylinder), oCyl);
0428 BOOST_CHECK_EQUAL(shell2.portal(OuterCylinder), oCyl);
0429
0430 BOOST_CHECK_EQUAL(stack.portal(PositiveDisc), shell2.portal(PositiveDisc));
0431 BOOST_CHECK_EQUAL(stack.portal(NegativeDisc), shell1.portal(NegativeDisc));
0432
0433 BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr);
0434 BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr);
0435
0436 BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr);
0437 BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr);
0438
0439 shell1 = SingleCylinderPortalShell{vol1};
0440 shell2 = SingleCylinderPortalShell{vol2};
0441
0442 BOOST_CHECK_THROW(CylinderStackPortalShell(gctx, {&shell1, &shell2},
0443 AxisDirection::AxisR),
0444 SurfaceMergingException);
0445 }
0446 }
0447
0448 BOOST_AUTO_TEST_CASE(RDirection) {
0449 using enum CylinderVolumeBounds::Face;
0450 BOOST_TEST_CONTEXT("rMin>0") {
0451 TrackingVolume vol1(
0452 Transform3::Identity(),
0453 std::make_shared<CylinderVolumeBounds>(30_mm, 100_mm, 100_mm));
0454
0455 TrackingVolume vol2(
0456 Transform3::Identity(),
0457 std::make_shared<CylinderVolumeBounds>(100_mm, 150_mm, 100_mm));
0458
0459 SingleCylinderPortalShell shell1{vol1};
0460 SingleCylinderPortalShell shell2{vol2};
0461
0462 BOOST_CHECK_NE(shell1.portal(OuterCylinder), shell2.portal(InnerCylinder));
0463
0464 CylinderStackPortalShell stack{
0465 gctx, {&shell1, &shell2}, AxisDirection::AxisR};
0466 BOOST_CHECK_EQUAL(stack.size(), 4);
0467
0468
0469 BOOST_CHECK_EQUAL(shell1.portal(OuterCylinder),
0470 shell2.portal(InnerCylinder));
0471
0472 const auto nDisc = stack.portal(NegativeDisc);
0473 const auto pDisc = stack.portal(PositiveDisc);
0474
0475 BOOST_CHECK_EQUAL(shell1.portal(NegativeDisc), nDisc);
0476 BOOST_CHECK_EQUAL(shell2.portal(NegativeDisc), nDisc);
0477 BOOST_CHECK_EQUAL(shell1.portal(PositiveDisc), pDisc);
0478 BOOST_CHECK_EQUAL(shell2.portal(PositiveDisc), pDisc);
0479 BOOST_CHECK_EQUAL(stack.portal(InnerCylinder),
0480 shell1.portal(InnerCylinder));
0481 BOOST_CHECK_EQUAL(stack.portal(OuterCylinder),
0482 shell2.portal(OuterCylinder));
0483 BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr);
0484 BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr);
0485
0486 BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr);
0487 BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr);
0488
0489 shell1 = SingleCylinderPortalShell{vol1};
0490 shell2 = SingleCylinderPortalShell{vol2};
0491
0492 BOOST_CHECK_THROW(CylinderStackPortalShell(gctx, {&shell1, &shell2},
0493 AxisDirection::AxisZ),
0494 SurfaceMergingException);
0495 }
0496
0497 BOOST_TEST_CONTEXT("rMin==0") {
0498 TrackingVolume vol1(
0499 Transform3::Identity(),
0500 std::make_shared<CylinderVolumeBounds>(0_mm, 100_mm, 100_mm));
0501
0502 TrackingVolume vol2(
0503 Transform3::Identity(),
0504 std::make_shared<CylinderVolumeBounds>(100_mm, 150_mm, 100_mm));
0505
0506 SingleCylinderPortalShell shell1{vol1};
0507 SingleCylinderPortalShell shell2{vol2};
0508
0509 BOOST_CHECK_EQUAL(shell1.portal(InnerCylinder), nullptr);
0510 BOOST_CHECK_NE(shell1.portal(OuterCylinder), shell2.portal(InnerCylinder));
0511
0512 CylinderStackPortalShell stack{
0513 gctx, {&shell1, &shell2}, AxisDirection::AxisR};
0514 BOOST_CHECK_EQUAL(stack.size(), 4);
0515
0516
0517 BOOST_CHECK_EQUAL(shell1.portal(OuterCylinder),
0518 shell2.portal(InnerCylinder));
0519
0520 const auto nDisc = stack.portal(NegativeDisc);
0521 const auto pDisc = stack.portal(PositiveDisc);
0522 BOOST_CHECK_EQUAL(shell1.portal(NegativeDisc), nDisc);
0523 BOOST_CHECK_EQUAL(shell2.portal(NegativeDisc), nDisc);
0524 BOOST_CHECK_EQUAL(shell1.portal(PositiveDisc), pDisc);
0525 BOOST_CHECK_EQUAL(shell2.portal(PositiveDisc), pDisc);
0526 BOOST_CHECK_EQUAL(stack.portal(InnerCylinder), nullptr);
0527 BOOST_CHECK_EQUAL(stack.portal(OuterCylinder),
0528 shell2.portal(OuterCylinder));
0529
0530 BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr);
0531 BOOST_CHECK_EQUAL(stack.portal(NegativePhiPlane), nullptr);
0532
0533 BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr);
0534 BOOST_CHECK_EQUAL(stack.portal(PositivePhiPlane), nullptr);
0535
0536 shell1 = SingleCylinderPortalShell{vol1};
0537 shell2 = SingleCylinderPortalShell{vol2};
0538
0539 BOOST_CHECK_THROW(CylinderStackPortalShell(gctx, {&shell1, &shell2},
0540 AxisDirection::AxisZ),
0541 std::invalid_argument);
0542 }
0543 }
0544
0545 BOOST_AUTO_TEST_CASE(NestedStacks) {
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570 Transform3 base = Transform3::Identity();
0571
0572 TrackingVolume vol1(
0573 base, std::make_shared<CylinderVolumeBounds>(23_mm, 48_mm, 200_mm),
0574 "PixelLayer0");
0575
0576 TrackingVolume gap(
0577 base, std::make_shared<CylinderVolumeBounds>(48_mm, 250_mm, 200_mm),
0578 "Gap");
0579
0580 TrackingVolume vol2(
0581 base, std::make_shared<CylinderVolumeBounds>(250_mm, 400_mm, 200_mm),
0582 "PixelLayer3");
0583
0584 TrackingVolume vol3(
0585 base * Translation3{Vector3::UnitZ() * 300_mm},
0586 std::make_shared<CylinderVolumeBounds>(23_mm, 400_mm, 100_mm),
0587 "PixelEcPos");
0588
0589 SingleCylinderPortalShell shell1{vol1};
0590 BOOST_CHECK(shell1.isValid());
0591 SingleCylinderPortalShell gapShell{gap};
0592 BOOST_CHECK(gapShell.isValid());
0593 SingleCylinderPortalShell shell2{vol2};
0594 BOOST_CHECK(shell2.isValid());
0595
0596 CylinderStackPortalShell stack{
0597 gctx, {&shell1, &gapShell, &shell2}, AxisDirection::AxisR};
0598
0599 BOOST_CHECK(stack.isValid());
0600
0601 SingleCylinderPortalShell shell3{vol3};
0602 BOOST_CHECK(shell3.isValid());
0603
0604 CylinderStackPortalShell stack2{
0605 gctx, {&stack, &shell3}, AxisDirection::AxisZ, *logger};
0606 BOOST_CHECK(stack2.isValid());
0607
0608 using enum CylinderVolumeBounds::Face;
0609
0610 auto lookup = [](auto& shell, CylinderPortalShell::Face face,
0611 Vector3 position,
0612 Vector3 direction) -> const TrackingVolume* {
0613 const auto portal = shell.portal(face);
0614 BOOST_REQUIRE_NE(portal, nullptr);
0615 return portal->resolveVolume(gctx, position, direction).value();
0616 };
0617
0618
0619
0620 BOOST_CHECK_EQUAL(lookup(shell1, InnerCylinder, 23_mm * Vector3::UnitX(),
0621 -Vector3::UnitX()),
0622 nullptr);
0623 BOOST_CHECK_EQUAL(
0624 lookup(shell1, InnerCylinder, 23_mm * Vector3::UnitX(), Vector3::UnitX()),
0625 &vol1);
0626
0627 BOOST_CHECK_EQUAL(
0628 lookup(shell1, OuterCylinder, 48_mm * Vector3::UnitX(), Vector3::UnitX()),
0629 &gap);
0630
0631 BOOST_CHECK_EQUAL(lookup(gapShell, InnerCylinder, 48_mm * Vector3::UnitX(),
0632 -Vector3::UnitX()),
0633 &vol1);
0634
0635 BOOST_CHECK_EQUAL(lookup(gapShell, OuterCylinder, 250_mm * Vector3::UnitX(),
0636 Vector3::UnitX()),
0637 &vol2);
0638
0639 BOOST_CHECK_EQUAL(lookup(shell2, InnerCylinder, 250_mm * Vector3::UnitX(),
0640 -Vector3::UnitX()),
0641 &gap);
0642
0643 BOOST_CHECK_EQUAL(lookup(shell2, OuterCylinder, 400_mm * Vector3::UnitX(),
0644 Vector3::UnitX()),
0645 nullptr);
0646
0647 BOOST_CHECK_EQUAL(lookup(shell2, OuterCylinder, 400_mm * Vector3::UnitX(),
0648 -Vector3::UnitX()),
0649 &vol2);
0650
0651 BOOST_CHECK_EQUAL(lookup(shell2, OuterCylinder, 400_mm * Vector3::UnitX(),
0652 -Vector3::UnitX()),
0653 &vol2);
0654
0655
0656
0657 BOOST_CHECK_EQUAL(lookup(shell1, NegativeDisc, Vector3(30_mm, 0, -200_mm),
0658 -Vector3::UnitZ()),
0659 nullptr);
0660
0661 BOOST_CHECK_EQUAL(lookup(shell1, NegativeDisc, Vector3(30_mm, 0, -200_mm),
0662 Vector3::UnitZ()),
0663 &vol1);
0664
0665 BOOST_CHECK_EQUAL(lookup(gapShell, NegativeDisc, Vector3(60_mm, 0, -200_mm),
0666 -Vector3::UnitZ()),
0667 nullptr);
0668
0669 BOOST_CHECK_EQUAL(lookup(gapShell, NegativeDisc, Vector3(60_mm, 0, -200_mm),
0670 Vector3::UnitZ()),
0671 &gap);
0672
0673 BOOST_CHECK_EQUAL(lookup(shell2, NegativeDisc, Vector3(300_mm, 0, -200_mm),
0674 -Vector3::UnitZ()),
0675 nullptr);
0676
0677 BOOST_CHECK_EQUAL(lookup(shell2, NegativeDisc, Vector3(300_mm, 0, -200_mm),
0678 Vector3::UnitZ()),
0679 &vol2);
0680
0681
0682
0683 BOOST_CHECK_EQUAL(lookup(shell1, PositiveDisc, Vector3(30_mm, 0, 200_mm),
0684 -Vector3::UnitZ()),
0685 &vol1);
0686
0687 BOOST_CHECK_EQUAL(
0688 lookup(shell1, PositiveDisc, Vector3(30_mm, 0, 200_mm), Vector3::UnitZ()),
0689 &vol3);
0690
0691 BOOST_CHECK_EQUAL(lookup(gapShell, PositiveDisc, Vector3(60_mm, 0, 200_mm),
0692 -Vector3::UnitZ()),
0693 &gap);
0694
0695 BOOST_CHECK_EQUAL(lookup(gapShell, PositiveDisc, Vector3(60_mm, 0, 200_mm),
0696 Vector3::UnitZ()),
0697 &vol3);
0698
0699 BOOST_CHECK_EQUAL(lookup(shell2, PositiveDisc, Vector3(300_mm, 0, 200_mm),
0700 -Vector3::UnitZ()),
0701 &vol2);
0702
0703 BOOST_CHECK_EQUAL(lookup(shell2, PositiveDisc, Vector3(300_mm, 0, 200_mm),
0704 Vector3::UnitZ()),
0705 &vol3);
0706
0707
0708
0709 BOOST_CHECK_EQUAL(lookup(shell3, PositiveDisc, Vector3(300_mm, 0, 400_mm),
0710 -Vector3::UnitZ()),
0711 &vol3);
0712
0713 BOOST_CHECK_EQUAL(lookup(shell3, PositiveDisc, Vector3(300_mm, 0, 400_mm),
0714 Vector3::UnitZ()),
0715 nullptr);
0716 }
0717
0718 BOOST_AUTO_TEST_CASE(Fill) {
0719 auto cyl1 = makeVolume(30_mm, 40_mm, 100_mm);
0720 auto cyl2 = makeVolume(0_mm, 50_mm, 110_mm);
0721
0722 SingleCylinderPortalShell shell{cyl1};
0723
0724 using enum CylinderVolumeBounds::Face;
0725 BOOST_CHECK_EQUAL(
0726 shell.portal(OuterCylinder)->getLink(Direction::AlongNormal()), nullptr);
0727 BOOST_CHECK_EQUAL(
0728 shell.portal(InnerCylinder)->getLink(Direction::OppositeNormal()),
0729 nullptr);
0730 BOOST_CHECK_EQUAL(
0731 shell.portal(PositiveDisc)->getLink(Direction::AlongNormal()), nullptr);
0732 BOOST_CHECK_EQUAL(
0733 shell.portal(NegativeDisc)->getLink(Direction::OppositeNormal()),
0734 nullptr);
0735
0736 shell.fill(cyl2);
0737
0738 BOOST_CHECK_NE(shell.portal(OuterCylinder)->getLink(Direction::AlongNormal()),
0739 nullptr);
0740 BOOST_CHECK_NE(
0741 shell.portal(InnerCylinder)->getLink(Direction::OppositeNormal()),
0742 nullptr);
0743 BOOST_CHECK_NE(shell.portal(PositiveDisc)->getLink(Direction::AlongNormal()),
0744 nullptr);
0745 BOOST_CHECK_NE(
0746 shell.portal(NegativeDisc)->getLink(Direction::OppositeNormal()),
0747 nullptr);
0748 }
0749
0750 BOOST_AUTO_TEST_CASE(RegisterInto) {
0751 using enum CylinderVolumeBounds::Face;
0752 TrackingVolume vol1(
0753 Transform3::Identity(),
0754 std::make_shared<CylinderVolumeBounds>(0_mm, 100_mm, 100_mm));
0755
0756 SingleCylinderPortalShell shell{vol1};
0757
0758 BOOST_CHECK_EQUAL(vol1.portals().size(), 0);
0759
0760 shell.applyToVolume();
0761 BOOST_CHECK_EQUAL(vol1.portals().size(), 3);
0762 }
0763
0764 BOOST_AUTO_TEST_SUITE_END()
0765 BOOST_AUTO_TEST_SUITE_END()
0766
0767 }