Skip to content

Commit

Permalink
feat: respect portal material when fusing portals (#2735)
Browse files Browse the repository at this point in the history
This PR introduces the correct handling of material when fusing portals.

The logic is as follows:
- if either of the to-be fused surfaces has material, it is being kept in the fusing process
- if both have material, an exception is thrown as this certainly indicates misconfiguration

A UnitTest is added to check for this behaviour.
  • Loading branch information
asalzburger authored Nov 29, 2023
1 parent ee8375f commit 6e0d5b1
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Core/include/Acts/Detector/Portal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ class Portal : public std::enable_shared_from_this<Portal> {
/// into this volume, it will throw an exception if the
/// portals are not fusable
///
/// @note if one portal carries material, it will be kept,
/// however, if both portals carry material, an exception
/// will be thrown and the portals are not fusable
///
/// @note that other will be overwritten to point to this
void fuse(std::shared_ptr<Portal>& other) noexcept(false);

Expand Down
10 changes: 10 additions & 0 deletions Core/src/Detector/Portal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ void Acts::Experimental::Portal::fuse(std::shared_ptr<Portal>& other) {
"Portal: trying to fuse portal (waste) with no links.");
}

if (m_surface->surfaceMaterial() != nullptr &&
other->surface().surfaceMaterial() != nullptr) {
throw std::runtime_error(
"Portal: both surfaces have surface material, fusing will lead to "
"information loss.");
} else if (other->surface().surfaceMaterial() != nullptr) {
m_surface->assignSurfaceMaterial(
other->surface().surfaceMaterialSharedPtr());
}

auto odx = oDir.index();
m_volumeUpdators[odx] = std::move(other->m_volumeUpdators[odx]);
m_attachedVolumes[odx] = other->m_attachedVolumes[odx];
Expand Down
89 changes: 89 additions & 0 deletions Tests/UnitTests/Core/Detector/PortalTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "Acts/Geometry/CuboidVolumeBounds.hpp"
#include "Acts/Geometry/GeometryContext.hpp"
#include "Acts/Geometry/GeometryIdentifier.hpp"
#include "Acts/Material/HomogeneousSurfaceMaterial.hpp"
#include "Acts/Material/MaterialSlab.hpp"
#include "Acts/Navigation/NavigationDelegates.hpp"
#include "Acts/Navigation/NavigationState.hpp"
#include "Acts/Navigation/SurfaceCandidatesUpdators.hpp"
Expand Down Expand Up @@ -168,4 +170,91 @@ BOOST_AUTO_TEST_CASE(PortalTest) {
BOOST_CHECK_THROW(portalAI->fuse(portalBI), std::runtime_error);
}

BOOST_AUTO_TEST_CASE(PortalMaterialTest) {
// Volume A and B
auto dTransform = Acts::Transform3::Identity();
auto pGenerator = defaultPortalGenerator();
auto volumeA = DetectorVolumeFactory::construct(
pGenerator, tContext, "dummyA", dTransform,
std::make_unique<Acts::CuboidVolumeBounds>(1, 1, 1),
tryAllPortalsAndSurfaces());
auto volumeB = DetectorVolumeFactory::construct(
pGenerator, tContext, "dummyB", dTransform,
std::make_unique<Acts::CuboidVolumeBounds>(1, 1, 1),
tryAllPortalsAndSurfaces());

// Create some material
auto materialSlab = Acts::MaterialSlab(
Acts::Material::fromMolarDensity(1., 2., 3., 4., 5.), 1.);
auto materialA =
std::make_shared<Acts::HomogeneousSurfaceMaterial>(materialSlab);
auto materialB =
std::make_shared<Acts::HomogeneousSurfaceMaterial>(materialSlab);

// A few portals
auto rectangle = std::make_shared<Acts::RectangleBounds>(10., 100.);

auto surfaceA = Acts::Surface::makeShared<Acts::PlaneSurface>(
Acts::Transform3::Identity(), rectangle);
surfaceA->assignSurfaceMaterial(materialA);
auto portalA = Acts::Experimental::Portal::makeShared(surfaceA);

DetectorVolumeUpdator linkToA;
auto linkToAImpl = std::make_unique<const LinkToVolumeImpl>(volumeA);
linkToA.connect<&LinkToVolumeImpl::link>(std::move(linkToAImpl));
portalA->assignDetectorVolumeUpdator(Acts::Direction::Positive,
std::move(linkToA), {volumeA});

auto surfaceB = Acts::Surface::makeShared<Acts::PlaneSurface>(
Acts::Transform3::Identity(), rectangle);
auto portalB = Acts::Experimental::Portal::makeShared(surfaceB);
DetectorVolumeUpdator linkToB;
auto linkToBImpl = std::make_unique<const LinkToVolumeImpl>(volumeB);
linkToB.connect<&LinkToVolumeImpl::link>(std::move(linkToBImpl));
portalB->assignDetectorVolumeUpdator(Acts::Direction::Negative,
std::move(linkToB), {volumeB});

// Portal A fuses with B
// - has material and keeps it, portal B becomes portal A
portalA->fuse(portalB);
BOOST_CHECK_EQUAL(portalA->surface().surfaceMaterial(), materialA.get());
BOOST_CHECK_EQUAL(portalA, portalB);

// Remake portal B
portalB = Acts::Experimental::Portal::makeShared(surfaceB);
DetectorVolumeUpdator linkToB2;
auto linkToB2Impl = std::make_unique<const LinkToVolumeImpl>(volumeB);
linkToB2.connect<&LinkToVolumeImpl::link>(std::move(linkToB2Impl));
portalB->assignDetectorVolumeUpdator(Acts::Direction::Negative,
std::move(linkToB2), {volumeB});

// Portal B fuses with A
// - A has material and keeps it, portal B gets it from A, A becomes B
BOOST_REQUIRE_NE(portalA, portalB);
portalB->fuse(portalA);
BOOST_CHECK_EQUAL(portalB->surface().surfaceMaterial(), materialA.get());
BOOST_CHECK_EQUAL(portalB, portalA);

// Remake portal A and B, this time both with material
portalA = Acts::Experimental::Portal::makeShared(surfaceA);
DetectorVolumeUpdator linkToA2;
auto linkToA2Impl = std::make_unique<const LinkToVolumeImpl>(volumeA);
linkToA2.connect<&LinkToVolumeImpl::link>(std::move(linkToA2Impl));
portalA->assignDetectorVolumeUpdator(Acts::Direction::Positive,
std::move(linkToA2), {volumeA});

surfaceB->assignSurfaceMaterial(materialB);
portalB = Acts::Experimental::Portal::makeShared(surfaceB);
DetectorVolumeUpdator linkToB3;
auto linkToB3Impl = std::make_unique<const LinkToVolumeImpl>(volumeB);
linkToB3.connect<&LinkToVolumeImpl::link>(std::move(linkToB3Impl));
portalB->assignDetectorVolumeUpdator(Acts::Direction::Negative,
std::move(linkToB3), {volumeB});

// Portal A fuses with B - both have material, throw exception
BOOST_CHECK_THROW(portalA->fuse(portalB), std::runtime_error);
// Same in reverse
BOOST_CHECK_THROW(portalB->fuse(portalA), std::runtime_error);
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 6e0d5b1

Please sign in to comment.