Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-23 08:24:07

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