File indexing completed on 2026-06-21 07:47: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/CompositePortalLink.hpp"
0016 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0017 #include "Acts/Geometry/GeometryContext.hpp"
0018 #include "Acts/Geometry/GridPortalLink.hpp"
0019 #include "Acts/Geometry/Portal.hpp"
0020 #include "Acts/Geometry/TrackingVolume.hpp"
0021 #include "Acts/Geometry/TrivialPortalLink.hpp"
0022 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
0023 #include "Acts/Material/MergedMaterialMarker.hpp"
0024 #include "Acts/Surfaces/CylinderSurface.hpp"
0025 #include "Acts/Surfaces/DiscSurface.hpp"
0026 #include "Acts/Surfaces/RadialBounds.hpp"
0027 #include "Acts/Surfaces/Surface.hpp"
0028 #include "Acts/Surfaces/SurfaceMergingException.hpp"
0029 #include "Acts/Utilities/ThrowAssert.hpp"
0030
0031 #include <stdexcept>
0032
0033 using namespace Acts;
0034 using namespace Acts::UnitLiterals;
0035
0036 namespace ActsTests {
0037
0038 auto logger = getDefaultLogger("UnitTests", Logging::VERBOSE);
0039
0040 struct Fixture {
0041 Logging::Level m_level;
0042 Fixture() {
0043 m_level = Logging::getFailureThreshold();
0044 Logging::setFailureThreshold(Logging::FATAL);
0045 }
0046
0047 ~Fixture() { Logging::setFailureThreshold(m_level); }
0048 };
0049
0050 std::shared_ptr<TrackingVolume> makeDummyVolume() {
0051 return std::make_shared<TrackingVolume>(
0052 Transform3::Identity(),
0053 std::make_shared<CylinderVolumeBounds>(30_mm, 40_mm, 100_mm));
0054 }
0055
0056 auto gctx = GeometryContext::dangerouslyDefaultConstruct();
0057
0058 BOOST_FIXTURE_TEST_SUITE(GeometrySuite, Fixture)
0059
0060 BOOST_AUTO_TEST_SUITE(Portals)
0061 BOOST_AUTO_TEST_SUITE(Merging)
0062
0063 BOOST_AUTO_TEST_CASE(Cylinder) {
0064 auto vol1 = makeDummyVolume();
0065 vol1->setVolumeName("vol1");
0066 auto vol2 = makeDummyVolume();
0067 vol2->setVolumeName("vol2");
0068
0069 auto cyl1 = Surface::makeShared<CylinderSurface>(
0070 Transform3{Translation3{Vector3::UnitZ() * -100_mm}}, 50_mm, 100_mm);
0071
0072 auto cyl2 = Surface::makeShared<CylinderSurface>(
0073 Transform3{Translation3{Vector3::UnitZ() * 100_mm}}, 50_mm, 100_mm);
0074
0075 Portal portal1{Direction::AlongNormal(),
0076 std::make_unique<TrivialPortalLink>(cyl1, *vol1)};
0077 BOOST_CHECK(portal1.isValid());
0078
0079 BOOST_CHECK_EQUAL(
0080 portal1
0081 .resolveVolume(gctx, Vector3{50_mm, 0_mm, -100_mm}, Vector3::UnitX())
0082 .value(),
0083 vol1.get());
0084
0085 BOOST_CHECK_EQUAL(
0086 portal1
0087 .resolveVolume(gctx, Vector3{50_mm, 0_mm, -100_mm}, -Vector3::UnitX())
0088 .value(),
0089 nullptr);
0090
0091 Portal portal2{Direction::AlongNormal(), cyl2, *vol2};
0092 BOOST_CHECK(portal2.isValid());
0093
0094 BOOST_CHECK_EQUAL(
0095 portal2
0096 .resolveVolume(gctx, Vector3{50_mm, 0_mm, 100_mm}, -Vector3::UnitX())
0097 .value(),
0098 nullptr);
0099
0100 BOOST_CHECK_EQUAL(
0101 portal2
0102 .resolveVolume(gctx, Vector3{50_mm, 0_mm, 100_mm}, Vector3::UnitX())
0103 .value(),
0104 vol2.get());
0105
0106 Portal portal3{gctx, std::make_unique<TrivialPortalLink>(cyl2, *vol2),
0107 nullptr};
0108 BOOST_CHECK(portal3.isValid());
0109
0110 BOOST_CHECK_NE(portal3.getLink(Direction::AlongNormal()), nullptr);
0111 BOOST_CHECK_EQUAL(portal3.getLink(Direction::OppositeNormal()), nullptr);
0112
0113 Portal portal4{gctx, nullptr,
0114 std::make_unique<TrivialPortalLink>(cyl2, *vol2)};
0115 BOOST_CHECK(portal4.isValid());
0116
0117 BOOST_CHECK_EQUAL(portal4.getLink(Direction::AlongNormal()), nullptr);
0118 BOOST_CHECK_NE(portal4.getLink(Direction::OppositeNormal()), nullptr);
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130 BOOST_CHECK_THROW(
0131 Portal::merge(gctx, portal1, portal4, AxisDirection::AxisZ, *logger),
0132 PortalMergingException);
0133
0134
0135
0136 BOOST_CHECK(portal1.isValid());
0137 BOOST_CHECK(portal2.isValid());
0138
0139 BOOST_CHECK_EQUAL(
0140 portal2.resolveVolume(gctx, Vector3{50_mm, 0_mm, 50_mm}, Vector3::UnitX())
0141 .value(),
0142 vol2.get());
0143
0144 BOOST_CHECK_EQUAL(
0145 portal2
0146 .resolveVolume(gctx, Vector3{50_mm, 0_mm, 50_mm}, -Vector3::UnitX())
0147 .value(),
0148 nullptr);
0149
0150
0151 BOOST_CHECK_THROW(
0152 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisRPhi, *logger),
0153 SurfaceMergingException);
0154
0155
0156
0157 BOOST_CHECK(!portal1.isValid());
0158 BOOST_CHECK(!portal2.isValid());
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168 portal1 = Portal{gctx, {.alongNormal = {cyl1, *vol1}}};
0169 portal2 = Portal{gctx, {.alongNormal = {cyl2, *vol2}}};
0170
0171 Portal merged12 =
0172 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisZ, *logger);
0173 BOOST_CHECK_NE(merged12.getLink(Direction::AlongNormal()), nullptr);
0174 BOOST_CHECK_EQUAL(merged12.getLink(Direction::OppositeNormal()), nullptr);
0175
0176 auto composite12 = dynamic_cast<const CompositePortalLink*>(
0177 merged12.getLink(Direction::AlongNormal()));
0178 BOOST_REQUIRE_NE(composite12, nullptr);
0179
0180 BOOST_CHECK_EQUAL(
0181 merged12
0182 .resolveVolume(gctx, Vector3{50_mm, 0_mm, -50_mm}, Vector3::UnitX())
0183 .value(),
0184 vol1.get());
0185
0186 BOOST_CHECK_EQUAL(
0187 merged12
0188 .resolveVolume(gctx, Vector3{50_mm, 0_mm, 50_mm}, Vector3::UnitX())
0189 .value(),
0190 vol2.get());
0191
0192 BOOST_CHECK_EQUAL(
0193 merged12
0194 .resolveVolume(gctx, Vector3{50_mm, 0_mm, -50_mm}, -Vector3::UnitX())
0195 .value(),
0196 nullptr);
0197
0198 BOOST_CHECK_EQUAL(
0199 merged12
0200 .resolveVolume(gctx, Vector3{50_mm, 0_mm, 50_mm}, -Vector3::UnitX())
0201 .value(),
0202 nullptr);
0203
0204 portal1 = Portal{gctx, {.alongNormal = {cyl1, *vol1}}};
0205
0206
0207 BOOST_CHECK_THROW(
0208 Portal::merge(gctx, portal1, portal1, AxisDirection::AxisZ, *logger),
0209 PortalMergingException);
0210
0211
0212 portal1 = Portal{gctx, {.alongNormal = {cyl1, *vol1}}};
0213 portal2 = Portal{gctx, {.alongNormal = {cyl1, *vol2}}};
0214 BOOST_CHECK_THROW(
0215 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisZ, *logger),
0216 AssertionFailureException);
0217
0218
0219 auto material = std::make_shared<HomogeneousSurfaceMaterial>(
0220 MaterialSlab::Nothing());
0221 cyl2->assignSurfaceMaterial(material);
0222 portal1 = Portal{gctx, {.alongNormal = {cyl1, *vol1}}};
0223 portal2 = Portal{gctx, {.alongNormal = {cyl2, *vol2}}};
0224 BOOST_CHECK_THROW(
0225 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisZ, *logger),
0226 PortalMergingException);
0227 }
0228
0229 BOOST_AUTO_TEST_CASE(Disc) {
0230 auto vol1 = makeDummyVolume();
0231 vol1->setVolumeName("vol1");
0232 auto vol2 = makeDummyVolume();
0233 vol2->setVolumeName("vol2");
0234 auto vol3 = makeDummyVolume();
0235 vol3->setVolumeName("vol3");
0236 auto vol4 = makeDummyVolume();
0237 vol4->setVolumeName("vol4");
0238
0239 auto disc1 = Surface::makeShared<DiscSurface>(
0240 Transform3::Identity(), std::make_shared<RadialBounds>(50_mm, 100_mm));
0241
0242 auto disc2 = Surface::makeShared<DiscSurface>(
0243 Transform3::Identity(), std::make_shared<RadialBounds>(100_mm, 150_mm));
0244
0245 Portal portal1{
0246 gctx, {.alongNormal = {disc1, *vol1}, .oppositeNormal = {disc1, *vol2}}};
0247
0248 Portal portal2{
0249 gctx, {.alongNormal = {disc2, *vol3}, .oppositeNormal = {disc2, *vol4}}};
0250
0251 BOOST_CHECK(portal1.isValid());
0252 BOOST_CHECK(portal2.isValid());
0253
0254 BOOST_CHECK_EQUAL(
0255 portal1.resolveVolume(gctx, Vector3{55_mm, 0_mm, 0_mm}, Vector3::UnitZ())
0256 .value(),
0257 vol1.get());
0258 BOOST_CHECK_EQUAL(
0259 portal1.resolveVolume(gctx, Vector3{55_mm, 0_mm, 0_mm}, -Vector3::UnitZ())
0260 .value(),
0261 vol2.get());
0262
0263 BOOST_CHECK_EQUAL(
0264 portal2.resolveVolume(gctx, Vector3{105_mm, 0_mm, 0_mm}, Vector3::UnitZ())
0265 .value(),
0266 vol3.get());
0267 BOOST_CHECK_EQUAL(
0268 portal2
0269 .resolveVolume(gctx, Vector3{105_mm, 0_mm, 0_mm}, -Vector3::UnitZ())
0270 .value(),
0271 vol4.get());
0272
0273 BOOST_CHECK_THROW(
0274 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisZ, *logger),
0275 AssertionFailureException);
0276
0277 BOOST_CHECK(portal1.isValid());
0278 BOOST_CHECK(portal2.isValid());
0279
0280 BOOST_CHECK_THROW(
0281 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisPhi, *logger),
0282 SurfaceMergingException);
0283
0284
0285
0286 BOOST_CHECK(!portal1.isValid());
0287 BOOST_CHECK(!portal2.isValid());
0288
0289
0290 portal1 = Portal{
0291 gctx, {.alongNormal = {disc1, *vol1}, .oppositeNormal = {disc1, *vol2}}};
0292
0293 portal2 = Portal{
0294 gctx, {.alongNormal = {disc2, *vol3}, .oppositeNormal = {disc2, *vol4}}};
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305 Portal merged12 =
0306 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisR, *logger);
0307
0308 BOOST_CHECK_EQUAL(
0309 merged12.resolveVolume(gctx, Vector3{55_mm, 0_mm, 0_mm}, Vector3::UnitZ())
0310 .value(),
0311 vol1.get());
0312 BOOST_CHECK_EQUAL(
0313 merged12
0314 .resolveVolume(gctx, Vector3{55_mm, 0_mm, 0_mm}, -Vector3::UnitZ())
0315 .value(),
0316 vol2.get());
0317
0318 BOOST_CHECK_EQUAL(
0319 merged12
0320 .resolveVolume(gctx, Vector3{105_mm, 0_mm, 0_mm}, Vector3::UnitZ())
0321 .value(),
0322 vol3.get());
0323 BOOST_CHECK_EQUAL(
0324 merged12
0325 .resolveVolume(gctx, Vector3{105_mm, 0_mm, 0_mm}, -Vector3::UnitZ())
0326 .value(),
0327 vol4.get());
0328
0329
0330 auto material = std::make_shared<HomogeneousSurfaceMaterial>(
0331 MaterialSlab::Nothing());
0332 disc2->assignSurfaceMaterial(material);
0333 portal1 = Portal{
0334 gctx, {.alongNormal = {disc1, *vol1}, .oppositeNormal = {disc1, *vol2}}};
0335 portal2 = Portal{
0336 gctx, {.alongNormal = {disc2, *vol3}, .oppositeNormal = {disc2, *vol4}}};
0337 BOOST_CHECK_THROW(
0338 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisR, *logger),
0339 PortalMergingException);
0340
0341
0342
0343 portal1 = Portal{
0344 gctx, {.alongNormal = {disc1, *vol1}, .oppositeNormal = {disc1, *vol2}}};
0345 portal2 = Portal{
0346 gctx, {.alongNormal = {disc2, *vol3}, .oppositeNormal = {disc2, *vol4}}};
0347 Portal mergedKeepGoing =
0348 Portal::merge(gctx, portal1, portal2, AxisDirection::AxisR, *logger,
0349 PortalMaterialMergePolicy::eDiscardAndMark);
0350 BOOST_CHECK(mergedKeepGoing.isValid());
0351 BOOST_REQUIRE(mergedKeepGoing.surface().surfaceMaterial() != nullptr);
0352 BOOST_CHECK(dynamic_cast<const MergedMaterialMarker*>(
0353 mergedKeepGoing.surface().surfaceMaterial()) != nullptr);
0354
0355 BOOST_CHECK(mergedKeepGoing.surface().surfaceMaterial()->materialSlab(
0356 Vector2{0., 0.}) == MaterialSlab::Nothing());
0357 }
0358
0359 BOOST_AUTO_TEST_SUITE_END()
0360
0361 BOOST_AUTO_TEST_SUITE(Fusing)
0362
0363 BOOST_AUTO_TEST_CASE(Separated) {
0364 auto vol1 = makeDummyVolume();
0365 vol1->setVolumeName("vol1");
0366 auto vol2 = makeDummyVolume();
0367 vol2->setVolumeName("vol2");
0368
0369 auto cyl1 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0370 50_mm, 100_mm);
0371
0372 auto cyl2 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0373 60_mm, 100_mm);
0374
0375 Portal portal1{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0376
0377 Portal portal2{gctx, {.alongNormal = {cyl2, *vol2}}};
0378
0379 BOOST_CHECK(portal1.isValid());
0380 BOOST_CHECK(portal2.isValid());
0381
0382
0383 BOOST_CHECK_THROW(Portal::fuse(gctx, portal1, portal2, *logger),
0384 PortalFusingException);
0385
0386 BOOST_CHECK(portal1.isValid());
0387 BOOST_CHECK(portal2.isValid());
0388
0389
0390 BOOST_CHECK_THROW(
0391 portal1.setLink(gctx, Direction::AlongNormal(), cyl2, *vol2),
0392 PortalFusingException);
0393 BOOST_CHECK_EQUAL(portal1.getLink(Direction::AlongNormal()), nullptr);
0394
0395 Portal portal1b{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0396 BOOST_CHECK(portal1b.isValid());
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406 BOOST_CHECK_THROW(Portal::fuse(gctx, portal1, portal1b, *logger),
0407 PortalFusingException);
0408 BOOST_CHECK(portal1.isValid());
0409 BOOST_CHECK(portal1b.isValid());
0410
0411 auto disc1 = Surface::makeShared<DiscSurface>(
0412 Transform3::Identity(), std::make_shared<RadialBounds>(50_mm, 100_mm));
0413
0414 auto disc2 = Surface::makeShared<DiscSurface>(
0415 Transform3{Translation3{Vector3{0, 0, 5_mm}}},
0416 std::make_shared<RadialBounds>(50_mm, 100_mm));
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426 Portal portal2b{gctx, {.alongNormal = {disc2, *vol2}}};
0427
0428 BOOST_CHECK_THROW(Portal::fuse(gctx, portal2, portal2b, *logger),
0429 PortalFusingException);
0430 BOOST_CHECK(portal1.isValid());
0431 BOOST_CHECK(portal2.isValid());
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441 Portal portal2c{
0442 gctx, {.alongNormal = {disc2, *vol1}, .oppositeNormal = {disc2, *vol2}}};
0443 BOOST_CHECK(portal2c.isValid());
0444
0445 BOOST_CHECK_THROW(Portal::fuse(gctx, portal2, portal2c, *logger),
0446 PortalFusingException);
0447 BOOST_CHECK(portal2.isValid());
0448 BOOST_CHECK(portal2c.isValid());
0449 }
0450
0451 BOOST_AUTO_TEST_CASE(Success) {
0452 auto vol1 = makeDummyVolume();
0453 vol1->setVolumeName("vol1");
0454 auto vol2 = makeDummyVolume();
0455 vol2->setVolumeName("vol2");
0456
0457 auto cyl1 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0458 50_mm, 100_mm);
0459
0460 auto cyl2 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0461 50_mm, 100_mm);
0462
0463 BOOST_CHECK(*cyl1 == *cyl2);
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473 Portal portal1{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0474 BOOST_CHECK_EQUAL(&portal1.getLink(Direction::OppositeNormal())->surface(),
0475 cyl1.get());
0476
0477 Portal portal2{gctx, {.alongNormal = {cyl2, *vol2}}};
0478
0479 BOOST_CHECK(portal1.isValid());
0480 BOOST_CHECK(portal2.isValid());
0481
0482 Portal portal3 = Portal::fuse(gctx, portal1, portal2, *logger);
0483
0484 BOOST_CHECK(!portal1.isValid());
0485 BOOST_CHECK(!portal2.isValid());
0486 BOOST_CHECK(portal3.isValid());
0487
0488 BOOST_CHECK_EQUAL(portal3.surface().surfaceMaterial(), nullptr);
0489
0490
0491 BOOST_CHECK_EQUAL(&portal3.surface(), cyl2.get());
0492
0493 BOOST_CHECK_EQUAL(&portal3.getLink(Direction::OppositeNormal())->surface(),
0494 cyl2.get());
0495 }
0496
0497 BOOST_AUTO_TEST_CASE(Material) {
0498 auto vol1 = makeDummyVolume();
0499 auto vol2 = makeDummyVolume();
0500
0501 auto cyl1 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0502 50_mm, 100_mm);
0503
0504 auto cyl2 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0505 50_mm, 100_mm);
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515 Portal portal1{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0516 Portal portal2{gctx, {.alongNormal = {cyl2, *vol2}}};
0517
0518 auto material = std::make_shared<HomogeneousSurfaceMaterial>(
0519 MaterialSlab::Nothing());
0520
0521 cyl1->assignSurfaceMaterial(material);
0522
0523 Portal portal12 = Portal::fuse(gctx, portal1, portal2, *logger);
0524
0525
0526 BOOST_CHECK_EQUAL(&portal12.surface(), cyl1.get());
0527 BOOST_CHECK_EQUAL(portal12.surface().surfaceMaterial(), material.get());
0528
0529
0530 portal1 = Portal{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0531 portal2 = Portal{gctx, {.alongNormal = {cyl2, *vol2}}};
0532 cyl2->assignSurfaceMaterial(material);
0533
0534
0535 BOOST_CHECK_THROW(Portal::fuse(gctx, portal1, portal2, *logger),
0536 PortalFusingException);
0537
0538 BOOST_CHECK(portal1.isValid());
0539 BOOST_CHECK(portal2.isValid());
0540
0541 cyl1->assignSurfaceMaterial(nullptr);
0542
0543 portal12 = Portal::fuse(gctx, portal1, portal2, *logger);
0544
0545
0546 BOOST_CHECK_EQUAL(&portal12.surface(), cyl2.get());
0547 BOOST_CHECK_EQUAL(portal12.surface().surfaceMaterial(), material.get());
0548 }
0549
0550 BOOST_AUTO_TEST_CASE(GridCreationOnFuse) {
0551 Transform3 base = Transform3::Identity();
0552
0553 auto vol1 = std::make_shared<TrackingVolume>(
0554 base, std::make_shared<CylinderVolumeBounds>(30_mm, 40_mm, 100_mm));
0555
0556 auto vol2 = std::make_shared<TrackingVolume>(
0557 base, std::make_shared<CylinderVolumeBounds>(30_mm, 40_mm, 100_mm));
0558
0559 auto vol3 = std::make_shared<TrackingVolume>(
0560 base, std::make_shared<CylinderVolumeBounds>(40_mm, 50_mm, 100_mm));
0561
0562 auto vol4 = std::make_shared<TrackingVolume>(
0563 base, std::make_shared<CylinderVolumeBounds>(40_mm, 50_mm, 100_mm));
0564
0565 auto disc1 =
0566 Surface::makeShared<DiscSurface>(Transform3::Identity(), 30_mm, 60_mm);
0567
0568 auto disc2 =
0569 Surface::makeShared<DiscSurface>(Transform3::Identity(), 60_mm, 90_mm);
0570
0571 auto disc3 =
0572 Surface::makeShared<DiscSurface>(Transform3::Identity(), 90_mm, 120_mm);
0573
0574 auto trivial1 = std::make_unique<TrivialPortalLink>(disc1, *vol1);
0575 BOOST_REQUIRE(trivial1);
0576 auto trivial2 = std::make_unique<TrivialPortalLink>(disc2, *vol2);
0577 BOOST_REQUIRE(trivial2);
0578 auto trivial3 = std::make_unique<TrivialPortalLink>(disc3, *vol3);
0579 BOOST_REQUIRE(trivial3);
0580
0581 std::vector<std::unique_ptr<PortalLinkBase>> links;
0582 links.push_back(std::move(trivial1));
0583 links.push_back(std::move(trivial2));
0584 links.push_back(std::move(trivial3));
0585
0586 auto composite = std::make_unique<CompositePortalLink>(std::move(links),
0587 AxisDirection::AxisR);
0588
0589 auto discOpposite =
0590 Surface::makeShared<DiscSurface>(Transform3::Identity(), 30_mm, 120_mm);
0591
0592 auto trivialOpposite =
0593 std::make_unique<TrivialPortalLink>(discOpposite, *vol4);
0594
0595 Portal aPortal{gctx, std::move(composite), nullptr};
0596 Portal bPortal{gctx, nullptr, std::move(trivialOpposite)};
0597
0598 Portal fused = Portal::fuse(gctx, aPortal, bPortal, *logger);
0599
0600 BOOST_CHECK_NE(dynamic_cast<const TrivialPortalLink*>(
0601 fused.getLink(Direction::OppositeNormal())),
0602 nullptr);
0603
0604 const auto* grid = dynamic_cast<const GridPortalLink*>(
0605 fused.getLink(Direction::AlongNormal()));
0606 BOOST_REQUIRE_NE(grid, nullptr);
0607
0608 BOOST_CHECK_EQUAL(grid->grid().axes().front()->getNBins(), 3);
0609 }
0610
0611 BOOST_AUTO_TEST_SUITE_END()
0612
0613 BOOST_AUTO_TEST_CASE(Construction) {
0614 auto vol1 = makeDummyVolume();
0615
0616
0617 auto disc1 = Surface::makeShared<DiscSurface>(
0618 Transform3::Identity(), std::make_shared<RadialBounds>(50_mm, 100_mm));
0619
0620 auto disc2 = Surface::makeShared<DiscSurface>(
0621 Transform3{Translation3{Vector3{0, 0, 5_mm}}},
0622 std::make_shared<RadialBounds>(50_mm, 100_mm));
0623
0624 BOOST_CHECK_THROW(std::make_unique<Portal>(
0625 gctx, std::make_unique<TrivialPortalLink>(disc1, *vol1),
0626 std::make_unique<TrivialPortalLink>(disc2, *vol1)),
0627 PortalFusingException);
0628
0629 BOOST_CHECK_THROW((Portal{gctx, nullptr, nullptr}), std::invalid_argument);
0630 BOOST_CHECK_THROW(Portal(gctx, {}), std::invalid_argument);
0631 }
0632
0633 BOOST_AUTO_TEST_CASE(InvalidConstruction) {
0634 BOOST_CHECK_THROW(Portal(Direction::AlongNormal(), nullptr),
0635 std::invalid_argument);
0636
0637 auto vol1 = makeDummyVolume();
0638
0639 BOOST_CHECK_THROW(Portal(Direction::AlongNormal(), nullptr, *vol1),
0640 std::invalid_argument);
0641
0642 auto disc1 = Surface::makeShared<DiscSurface>(
0643 Transform3::Identity(), std::make_shared<RadialBounds>(50_mm, 100_mm));
0644 Portal portal(Direction::AlongNormal(), disc1, *vol1);
0645
0646 BOOST_CHECK_THROW(portal.setLink(gctx, Direction::AlongNormal(), nullptr),
0647 std::invalid_argument);
0648 }
0649
0650 BOOST_AUTO_TEST_CASE(PortalFill) {
0651 auto vol1 = makeDummyVolume();
0652 auto vol2 = makeDummyVolume();
0653
0654 auto cyl1 = Surface::makeShared<CylinderSurface>(Transform3::Identity(),
0655 50_mm, 100_mm);
0656
0657 Portal portal1{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0658 Portal portal2{gctx, {.alongNormal = {cyl1, *vol2}}};
0659
0660
0661 Portal::fuse(gctx, portal1, portal2, *logger);
0662
0663 BOOST_CHECK_THROW(portal1.fill(*vol2), std::logic_error);
0664
0665 portal1 = Portal{gctx, {.oppositeNormal = {cyl1, *vol1}}};
0666 portal2 = Portal{gctx, {.alongNormal = {cyl1, *vol2}}};
0667
0668 BOOST_CHECK_EQUAL(portal1.getLink(Direction::AlongNormal()), nullptr);
0669 BOOST_CHECK_NE(portal1.getLink(Direction::OppositeNormal()), nullptr);
0670
0671 portal1.fill(*vol2);
0672 BOOST_CHECK_NE(portal1.getLink(Direction::AlongNormal()), nullptr);
0673 BOOST_CHECK_NE(portal1.getLink(Direction::OppositeNormal()), nullptr);
0674
0675 BOOST_CHECK_THROW(portal1.fill(*vol2), std::logic_error);
0676 }
0677
0678 BOOST_AUTO_TEST_SUITE_END()
0679
0680 BOOST_AUTO_TEST_SUITE_END()
0681
0682 }