File indexing completed on 2025-10-16 08:04:01
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Detector/DetectorVolume.hpp"
0013 #include "Acts/Detector/Portal.hpp"
0014 #include "Acts/Detector/PortalGenerators.hpp"
0015 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0016 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0017 #include "Acts/Geometry/Extent.hpp"
0018 #include "Acts/Geometry/GeometryContext.hpp"
0019 #include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
0020 #include "Acts/Material/HomogeneousVolumeMaterial.hpp"
0021 #include "Acts/Material/Material.hpp"
0022 #include "Acts/Material/MaterialSlab.hpp"
0023 #include "Acts/Navigation/DetectorVolumeFinders.hpp"
0024 #include "Acts/Navigation/InternalNavigation.hpp"
0025 #include "Acts/Navigation/NavigationState.hpp"
0026 #include "Acts/Surfaces/CylinderBounds.hpp"
0027 #include "Acts/Surfaces/CylinderSurface.hpp"
0028 #include "Acts/Surfaces/PlaneSurface.hpp"
0029 #include "Acts/Surfaces/RectangleBounds.hpp"
0030 #include "Acts/Surfaces/Surface.hpp"
0031 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0032
0033 #include <cstddef>
0034 #include <memory>
0035 #include <stdexcept>
0036 #include <utility>
0037 #include <vector>
0038
0039
0040
0041
0042
0043
0044
0045
0046 template <typename referenced_type>
0047 std::shared_ptr<referenced_type> unpackToShared(referenced_type& rt) {
0048 return rt.getSharedPtr();
0049 }
0050
0051 using namespace Acts;
0052 using namespace Acts::Experimental;
0053
0054 GeometryContext tContext;
0055
0056 namespace ActsTests {
0057
0058 BOOST_AUTO_TEST_SUITE(DetectorSuite)
0059
0060 BOOST_AUTO_TEST_CASE(SurfaceVolumeContainment) {
0061
0062 auto surfaceOutOfBounds = Surface::makeShared<CylinderSurface>(
0063 Transform3::Identity() * Translation3(-1000, 0., 0.),
0064 std::make_shared<CylinderBounds>(1, 1));
0065
0066 auto vBounds = CuboidVolumeBounds(10.0, 10.0, 10.0);
0067 auto portalGenerator = Experimental::defaultPortalAndSubPortalGenerator();
0068 BOOST_CHECK_THROW(
0069 Experimental::DetectorVolumeFactory::construct(
0070 portalGenerator, GeometryContext(), "CubeWithOutofBoundsSurface",
0071 Transform3::Identity(), std::make_shared<CuboidVolumeBounds>(vBounds),
0072 {surfaceOutOfBounds}, {}, Experimental::tryAllSubVolumes(),
0073 Experimental::tryAllPortalsAndSurfaces(), 1000),
0074 std::invalid_argument);
0075
0076
0077 auto surfaceTooBig = Surface::makeShared<PlaneSurface>(
0078 Transform3::Identity() * Translation3(0, 0., 0.),
0079 std::make_shared<RectangleBounds>(1, 100));
0080
0081 BOOST_CHECK_THROW(
0082 Experimental::DetectorVolumeFactory::construct(
0083 portalGenerator, GeometryContext(), "CubeWithSurfaceTooBig",
0084 Transform3::Identity(), std::make_shared<CuboidVolumeBounds>(vBounds),
0085 {surfaceTooBig}, {}, Experimental::tryAllSubVolumes(),
0086 Experimental::tryAllPortalsAndSurfaces(), 1000),
0087 std::invalid_argument);
0088
0089
0090 auto bigVolume = Experimental::DetectorVolumeFactory::construct(
0091 portalGenerator, GeometryContext(), "BigCube", Transform3::Identity(),
0092 std::make_shared<CuboidVolumeBounds>(vBounds), {}, {},
0093 Experimental::tryAllSubVolumes(),
0094 Experimental::tryAllPortalsAndSurfaces(), 1000);
0095
0096 auto smallBounds = CuboidVolumeBounds(1.0, 1.0, 1.0);
0097 BOOST_CHECK_THROW(Experimental::DetectorVolumeFactory::construct(
0098 portalGenerator, GeometryContext(),
0099 "SmallCubeWithBigCubeInside", Transform3::Identity(),
0100 std::make_shared<CuboidVolumeBounds>(smallBounds), {},
0101 {bigVolume}, Experimental::tryAllSubVolumes(),
0102 Experimental::tryAllPortalsAndSurfaces(), 1000),
0103 std::invalid_argument);
0104
0105
0106 auto smallVolumeMisaligned = Experimental::DetectorVolumeFactory::construct(
0107 portalGenerator, GeometryContext(), "SmallCubeMisaligned",
0108 Transform3::Identity() * Translation3(9.5, 0., 0.),
0109 std::make_shared<CuboidVolumeBounds>(smallBounds), {}, {},
0110 Experimental::tryAllSubVolumes(),
0111 Experimental::tryAllPortalsAndSurfaces(), 1000);
0112
0113 BOOST_CHECK_THROW(
0114 Experimental::DetectorVolumeFactory::construct(
0115 portalGenerator, GeometryContext(), "CubeWithMisalignedVolume",
0116 Transform3::Identity(), std::make_shared<CuboidVolumeBounds>(vBounds),
0117 {}, {smallVolumeMisaligned}, Experimental::tryAllSubVolumes(),
0118 Experimental::tryAllPortalsAndSurfaces(), 1000),
0119 std::invalid_argument);
0120 }
0121
0122 BOOST_AUTO_TEST_CASE(CylindricalDetectorVolumePortals) {
0123 double rInner = 10.;
0124 double rOuter = 100.;
0125 double zHalfL = 200.;
0126
0127 Transform3 nominal = Transform3::Identity();
0128
0129 auto fullCylinderBounds =
0130 std::make_unique<CylinderVolumeBounds>(0., rOuter, zHalfL);
0131
0132 auto portalGenerator = defaultPortalGenerator();
0133
0134
0135 BOOST_CHECK_THROW(
0136 DetectorVolumeFactory::construct(portalGenerator, tContext,
0137 "MisconfiguredFullCylinderVolume",
0138 nominal, nullptr, tryAllPortals()),
0139 std::invalid_argument);
0140
0141
0142 PortalGenerator unconnected;
0143 BOOST_CHECK_THROW(
0144 DetectorVolumeFactory::construct(unconnected, tContext,
0145 "MisconfiguredFullCylinderVolume",
0146 nominal, nullptr, tryAllPortals()),
0147 std::invalid_argument);
0148
0149
0150 auto fullCylinderVolume = DetectorVolumeFactory::construct(
0151 portalGenerator, tContext, "FullCylinderVolume", nominal,
0152 std::move(fullCylinderBounds), tryAllPortals());
0153
0154 BOOST_CHECK_EQUAL(fullCylinderVolume,
0155 unpackToShared<DetectorVolume>(*fullCylinderVolume));
0156 BOOST_CHECK_EQUAL(fullCylinderVolume,
0157 unpackToShared<const DetectorVolume>(*fullCylinderVolume));
0158
0159 BOOST_CHECK(fullCylinderVolume->surfaces().empty());
0160 BOOST_CHECK(fullCylinderVolume->volumes().empty());
0161 BOOST_CHECK_EQUAL(fullCylinderVolume->portals().size(), 3u);
0162
0163
0164 auto tubeCylinderBounds =
0165 std::make_unique<CylinderVolumeBounds>(rInner, rOuter, zHalfL);
0166
0167 auto tubeCylinderVolume = DetectorVolumeFactory::construct(
0168 portalGenerator, tContext, "TubeCylinderVolume", nominal,
0169 std::move(tubeCylinderBounds), tryAllPortals());
0170
0171 BOOST_CHECK(tubeCylinderVolume->surfaces().empty());
0172 BOOST_CHECK(tubeCylinderVolume->volumes().empty());
0173 BOOST_CHECK_EQUAL(tubeCylinderVolume->portals().size(), 4u);
0174
0175
0176 BOOST_CHECK(tubeCylinderVolume->inside(tContext, Vector3(50., 0., 0.)));
0177
0178 BOOST_CHECK(!tubeCylinderVolume->inside(tContext, Vector3(150., 0., 0.)));
0179
0180
0181 auto volumeExtent = tubeCylinderVolume->extent(tContext, 1);
0182 CHECK_CLOSE_ABS(volumeExtent.min(AxisDirection::AxisR), 10., 10e-5);
0183 CHECK_CLOSE_ABS(volumeExtent.max(AxisDirection::AxisR), 100., 10e-5);
0184 CHECK_CLOSE_ABS(volumeExtent.min(AxisDirection::AxisZ), -200., 10e-5);
0185 CHECK_CLOSE_ABS(volumeExtent.max(AxisDirection::AxisZ), 200., 10e-5);
0186 }
0187
0188 BOOST_AUTO_TEST_CASE(UpdatePortal) {
0189 Transform3 nominal = Transform3::Identity();
0190
0191 auto fullCylinderBounds =
0192 std::make_unique<CylinderVolumeBounds>(0., 10., 100.);
0193
0194 auto portalGenerator = defaultPortalGenerator();
0195
0196 auto fullCylinderVolume = DetectorVolumeFactory::construct(
0197 portalGenerator, tContext, "FullCylinderVolume", nominal,
0198 std::move(fullCylinderBounds), tryAllPortals());
0199
0200 auto cylinderSurface =
0201 Surface::makeShared<CylinderSurface>(nominal, 10., 100.);
0202
0203 auto cylinderPortal = std::make_shared<Experimental::Portal>(cylinderSurface);
0204
0205 fullCylinderVolume->updatePortal(cylinderPortal, 2u);
0206
0207 BOOST_CHECK_EQUAL(fullCylinderVolume->portals()[2u], cylinderPortal.get());
0208 }
0209
0210 BOOST_AUTO_TEST_CASE(CuboidWithCuboid) {
0211 double bigBox = 100.;
0212 double smallBox = 10.;
0213
0214 Transform3 nominal = Transform3::Identity();
0215
0216 auto bigBoxBounds =
0217 std::make_unique<CuboidVolumeBounds>(bigBox, bigBox, bigBox);
0218
0219 auto smallBoxBounds =
0220 std::make_unique<CuboidVolumeBounds>(smallBox, smallBox, smallBox);
0221
0222 auto portals = defaultPortalGenerator();
0223 auto generatePortalsUpdateInternals = defaultPortalAndSubPortalGenerator();
0224
0225
0226 auto innerBox = DetectorVolumeFactory::construct(
0227 portals, tContext, "InnerBox", nominal, std::move(smallBoxBounds),
0228 tryAllPortals());
0229
0230 std::vector<std::shared_ptr<Surface>> surfaces = {};
0231 std::vector<std::shared_ptr<Experimental::DetectorVolume>> volumes = {
0232 innerBox};
0233
0234
0235
0236 auto outerBox = DetectorVolumeFactory::construct(
0237 generatePortalsUpdateInternals, tContext, "OuterBox", nominal,
0238 std::move(bigBoxBounds), surfaces, volumes, tryAllSubVolumes(),
0239 tryAllPortals());
0240
0241
0242 Experimental::NavigationState nState;
0243 nState.position = Vector3(-50., 5., 0.);
0244 nState.direction = Vector3(1., 0., 0.);
0245
0246 BOOST_CHECK(outerBox->inside(tContext, nState.position));
0247 nState.currentVolume = outerBox.get();
0248
0249 outerBox->updateNavigationState(tContext, nState);
0250
0251
0252
0253 BOOST_CHECK_EQUAL(nState.surfaceCandidates.size(), 3u);
0254
0255
0256
0257 std::size_t nSurfaces = 0;
0258 outerBox->visitSurfaces([&nSurfaces](const auto* s) {
0259 if (s != nullptr) {
0260 nSurfaces++;
0261 }
0262 });
0263
0264 BOOST_CHECK_EQUAL(nSurfaces, 12u);
0265
0266
0267 std::size_t nVolumes = 0;
0268 outerBox->visitVolumes([&nVolumes](const auto* v) {
0269 if (v != nullptr) {
0270 nVolumes++;
0271 }
0272 });
0273 BOOST_CHECK_EQUAL(nVolumes, 2u);
0274
0275
0276
0277 struct SetMaterial {
0278
0279 std::shared_ptr<const HomogeneousSurfaceMaterial> surfaceMaterial =
0280 std::make_shared<HomogeneousSurfaceMaterial>(
0281 MaterialSlab(Material::fromMolarDensity(1., 2., 3., 4., 5.), 1.));
0282
0283 std::shared_ptr<HomogeneousVolumeMaterial> volumeMaterial =
0284 std::make_shared<HomogeneousVolumeMaterial>(
0285 Material::fromMolarDensity(1., 2., 3., 4., 5.));
0286
0287
0288 void operator()(Surface* s) {
0289 if (s != nullptr) {
0290 s->assignSurfaceMaterial(surfaceMaterial);
0291 }
0292 }
0293
0294
0295 void operator()(DetectorVolume* v) {
0296 if (v != nullptr) {
0297 v->assignVolumeMaterial(volumeMaterial);
0298 }
0299 }
0300 };
0301
0302 SetMaterial setMaterial;
0303 outerBox->visitMutableSurfaces(setMaterial);
0304 outerBox->visitMutableVolumes(setMaterial);
0305
0306
0307 std::size_t nSurfacesWithMaterial = 0;
0308 outerBox->visitSurfaces([&nSurfacesWithMaterial](const auto* s) {
0309 if (s != nullptr && s->surfaceMaterial() != nullptr) {
0310 nSurfacesWithMaterial++;
0311 }
0312 });
0313 BOOST_CHECK_EQUAL(nSurfacesWithMaterial, 12u);
0314
0315
0316 std::size_t nVolumesWithMaterial = 0;
0317 outerBox->visitVolumes([&nVolumesWithMaterial](const auto* v) {
0318 if (v != nullptr && v->volumeMaterial() != nullptr) {
0319 nVolumesWithMaterial++;
0320 }
0321 });
0322 BOOST_CHECK_EQUAL(nVolumesWithMaterial, 2u);
0323 }
0324
0325 BOOST_AUTO_TEST_CASE(CylinderWithSurfacesTestExtractors) {
0326 auto portalGenerator = defaultPortalGenerator();
0327
0328 std::vector<double> radii = {100, 102, 104, 106, 108, 110};
0329 auto cylinderVoumeBounds =
0330 std::make_unique<CylinderVolumeBounds>(80, 130, 200);
0331 std::vector<std::shared_ptr<Surface>> surfaces = {};
0332 for (const auto& r : radii) {
0333 surfaces.push_back(Surface::makeShared<CylinderSurface>(
0334 Transform3::Identity(), std::make_shared<CylinderBounds>(r, 190)));
0335 }
0336
0337
0338 auto cylinderVolume = DetectorVolumeFactory::construct(
0339 portalGenerator, tContext, "CylinderVolume", Transform3::Identity(),
0340 std::move(cylinderVoumeBounds), surfaces, {}, tryNoVolumes(),
0341 tryAllPortalsAndSurfaces());
0342
0343
0344 NavigationState nState;
0345 AllPortalsExtractor allPortals;
0346 AllSurfacesExtractor allSurfaces;
0347 IndexedSurfacesExtractor indexedSurfaces;
0348
0349
0350 BOOST_CHECK_THROW(allPortals.extract(tContext, nState), std::runtime_error);
0351 BOOST_CHECK_THROW(allSurfaces.extract(tContext, nState), std::runtime_error);
0352 BOOST_CHECK_THROW(indexedSurfaces.extract(tContext, nState, {0u, 1u}),
0353 std::runtime_error);
0354
0355
0356 nState.currentVolume = cylinderVolume.get();
0357
0358
0359 auto eportals = allPortals.extract(tContext, nState);
0360 BOOST_CHECK_EQUAL(eportals.size(), 4u);
0361
0362 auto esurfaces = allSurfaces.extract(tContext, nState);
0363 BOOST_CHECK_EQUAL(esurfaces.size(), 6u);
0364
0365 esurfaces = indexedSurfaces.extract(tContext, nState, {2u, 4u});
0366 BOOST_CHECK_EQUAL(esurfaces.size(), 2u);
0367 BOOST_CHECK_EQUAL(esurfaces[0u], surfaces[2u].get());
0368 BOOST_CHECK_EQUAL(esurfaces[1u], surfaces[4u].get());
0369
0370
0371 struct CountSurfaces {
0372 unsigned int counter = 0;
0373
0374 void operator()(const Surface* s) {
0375 if (s != nullptr) {
0376 counter++;
0377 }
0378 }
0379 };
0380
0381 CountSurfaces countSurfaces;
0382 cylinderVolume->visitSurfaces(countSurfaces);
0383
0384
0385 BOOST_CHECK_EQUAL(countSurfaces.counter, 10u);
0386 }
0387
0388 BOOST_AUTO_TEST_SUITE_END()
0389
0390 }