File indexing completed on 2026-05-08 08:01:24
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/tools/old/interface.hpp>
0010 #include <boost/test/tree/test_unit.hpp>
0011 #include <boost/test/unit_test.hpp>
0012
0013 #include "Acts/Definitions/Algebra.hpp"
0014 #include "Acts/Definitions/Direction.hpp"
0015 #include "Acts/Geometry/Blueprint.hpp"
0016 #include "Acts/Geometry/CompositePortalLink.hpp"
0017 #include "Acts/Geometry/CuboidVolumeBounds.hpp"
0018 #include "Acts/Geometry/CylinderVolumeBounds.hpp"
0019 #include "Acts/Geometry/CylinderVolumeHelper.hpp"
0020 #include "Acts/Geometry/GeometryContext.hpp"
0021 #include "Acts/Geometry/GridPortalLink.hpp"
0022 #include "Acts/Geometry/LayerBlueprintNode.hpp"
0023 #include "Acts/Geometry/Portal.hpp"
0024 #include "Acts/Geometry/TrackingGeometry.hpp"
0025 #include "Acts/Geometry/TrackingVolume.hpp"
0026 #include "Acts/Geometry/TrivialPortalLink.hpp"
0027 #include "Acts/MagneticField/ConstantBField.hpp"
0028 #include "Acts/Navigation/MultiLayerNavigationPolicy.hpp"
0029 #include "Acts/Navigation/TryAllNavigationPolicy.hpp"
0030 #include "Acts/Propagator/EigenStepper.hpp"
0031 #include "Acts/Propagator/Navigator.hpp"
0032 #include "Acts/Propagator/Propagator.hpp"
0033 #include "Acts/Surfaces/PlaneSurface.hpp"
0034 #include "Acts/Surfaces/RectangleBounds.hpp"
0035 #include "Acts/Surfaces/Surface.hpp"
0036 #include "Acts/Utilities/AnyGridView.hpp"
0037 #include "Acts/Utilities/Axis.hpp"
0038 #include "Acts/Utilities/AxisDefinitions.hpp"
0039 #include "Acts/Utilities/Logger.hpp"
0040 #include "ActsPlugins/Json/TrackingGeometryJsonConverter.hpp"
0041 #include "ActsTests/CommonHelpers/CylindricalTrackingGeometry.hpp"
0042 #include "ActsTests/CommonHelpers/TemporaryDirectory.hpp"
0043
0044 #include <cstddef>
0045 #include <fstream>
0046 #include <functional>
0047 #include <memory>
0048 #include <utility>
0049 #include <vector>
0050
0051 namespace ActsTests {
0052
0053 using namespace Acts;
0054 using namespace Experimental;
0055 using namespace UnitLiterals;
0056 using enum CylinderVolumeBounds::Face;
0057 using enum AxisDirection;
0058
0059 using ConstantFieldStepper = Acts::EigenStepper<>;
0060 using ConstantFieldPropagator =
0061 Acts::Propagator<ConstantFieldStepper, Acts::Navigator>;
0062
0063 template <typename navigator_t = Navigator,
0064 typename stepper_t = ConstantFieldStepper>
0065 struct StateCollector {
0066 struct this_result {
0067 std::vector<typename navigator_t::State> navigation;
0068 std::vector<typename stepper_t::State> stepping;
0069 };
0070
0071 using result_type = this_result;
0072
0073 template <typename propagator_state_t>
0074 Result<void> act(propagator_state_t& state, const stepper_t& ,
0075 const navigator_t& , result_type& result,
0076 const Logger& ) const {
0077 result.navigation.push_back(state.navigation);
0078 result.stepping.push_back(state.stepping);
0079 return {};
0080 }
0081 };
0082
0083 void checkHierarchy(const GeometryContext& gctx,
0084 const TrackingVolume::VolumeRange& volsA,
0085 const TrackingVolume::VolumeRange& volsB) {
0086 auto checkSurfaces = [&](const auto& surfA, const auto& surfB) {
0087 BOOST_CHECK_EQUAL(surfA.type(), surfB.type());
0088 BOOST_CHECK_EQUAL(surfA.geometryId(), surfB.geometryId());
0089 BOOST_CHECK_EQUAL(surfA.bounds(), surfB.bounds());
0090
0091 BOOST_CHECK_LT((surfA.localToGlobalTransform(gctx).matrix() -
0092 surfB.localToGlobalTransform(gctx).matrix())
0093 .norm(),
0094 1e-10);
0095 const auto* matA = surfA.surfaceMaterial();
0096 const auto* matB = surfB.surfaceMaterial();
0097 if (matA != nullptr) {
0098 BOOST_REQUIRE_NE(matB, nullptr);
0099 BOOST_CHECK_EQUAL(surfA.surfaceMaterial()->materialSlab(Vector2{0, 0}),
0100 surfB.surfaceMaterial()->materialSlab(Vector2{0, 0}));
0101 }
0102 };
0103 std::function<void(const Acts::PortalLinkBase* linkA,
0104 const Acts::PortalLinkBase* linkB)>
0105 checkLinks = [&](const auto* linkA, const auto* linkB) {
0106 const auto* trivialA =
0107 dynamic_cast<const Acts::TrivialPortalLink*>(linkA);
0108 const auto* trivialB =
0109 dynamic_cast<const Acts::TrivialPortalLink*>(linkB);
0110 if (trivialA != nullptr) {
0111 BOOST_REQUIRE_NE(trivialB, nullptr);
0112 BOOST_CHECK(trivialA->volume() == trivialB->volume());
0113 checkSurfaces(trivialA->surface(), trivialB->surface());
0114 }
0115
0116 const auto* gridA = dynamic_cast<const Acts::GridPortalLink*>(linkA);
0117 const auto* gridB = dynamic_cast<const Acts::GridPortalLink*>(linkB);
0118 if (gridA != nullptr) {
0119 BOOST_REQUIRE_NE(gridB, nullptr);
0120 BOOST_CHECK_EQUAL(gridA->dim(), gridB->dim());
0121 BOOST_CHECK_EQUAL(gridA->direction(), gridB->direction());
0122 BOOST_CHECK(gridA->grid() == gridB->grid());
0123 checkSurfaces(gridA->surface(), gridB->surface());
0124
0125 const auto& childrenA = gridA->artifactPortalLinks();
0126 const auto& childrenB = gridA->artifactPortalLinks();
0127 for (std::size_t i = 0; i < childrenA.size(); i++) {
0128 const auto& childA = *(childrenA.begin() + i);
0129 const auto& childB = *(childrenB.begin() + i);
0130 checkLinks(&childA, &childB);
0131 }
0132 }
0133
0134 const auto* compositeA =
0135 dynamic_cast<const Acts::CompositePortalLink*>(linkA);
0136 const auto* compositeB =
0137 dynamic_cast<const Acts::CompositePortalLink*>(linkB);
0138 if (compositeA != nullptr) {
0139 BOOST_REQUIRE_NE(compositeB, nullptr);
0140 const auto& childrenA = compositeA->links();
0141 const auto& childrenB = compositeB->links();
0142 for (std::size_t i = 0; i < childrenA.size(); i++) {
0143 const auto& childA = childrenA.at(i);
0144 const auto& childB = childrenB.at(i);
0145 checkLinks(&childA, &childB);
0146 }
0147 }
0148 };
0149
0150 BOOST_CHECK_EQUAL(volsA.size(), volsB.size());
0151 for (std::size_t i = 0; i < volsA.size(); i++) {
0152 const auto& volA = volsA.at(i);
0153 const auto& volB = volsB.at(i);
0154 BOOST_CHECK(volA == volB);
0155
0156 const auto& surfsA = volA.surfaces();
0157 const auto& surfsB = volB.surfaces();
0158 BOOST_CHECK_EQUAL(surfsA.size(), surfsB.size());
0159 for (std::size_t j = 0; j < surfsA.size(); j++) {
0160 checkSurfaces(surfsA.at(i), surfsB.at(i));
0161 }
0162
0163 const auto& portsA = volA.portals();
0164 const auto& portsB = volB.portals();
0165 BOOST_CHECK_EQUAL(portsA.size(), portsB.size());
0166 for (std::size_t j = 0; j < portsA.size(); j++) {
0167 const auto& portA = portsA.at(j);
0168 const auto& portB = portsB.at(j);
0169
0170 const auto& surfA = portA.surface();
0171 const auto& surfB = portB.surface();
0172 checkSurfaces(surfA, surfB);
0173
0174 const auto* alongA = portA.getLink(Acts::Direction::AlongNormal());
0175 const auto* alongB = portB.getLink(Acts::Direction::AlongNormal());
0176 checkLinks(alongA, alongB);
0177
0178 const auto* oppositeA = portA.getLink(Acts::Direction::OppositeNormal());
0179 const auto* oppositeB = portB.getLink(Acts::Direction::OppositeNormal());
0180 checkLinks(oppositeA, oppositeB);
0181 }
0182 checkHierarchy(gctx, volA.volumes(), volB.volumes());
0183 }
0184 }
0185
0186 auto logger = getDefaultLogger("UnitTests", Logging::INFO);
0187
0188 BOOST_AUTO_TEST_SUITE(JsonSuite)
0189
0190 BOOST_AUTO_TEST_CASE(TrackingGeometryJsonConverterRoundTrip) {
0191 using namespace Acts;
0192
0193 GeometryContext gctx = GeometryContext::dangerouslyDefaultConstruct();
0194
0195 TryAllNavigationPolicy::Config tryAllConfig;
0196 tryAllConfig.portals = true;
0197 tryAllConfig.sensitives = false;
0198 std::unique_ptr<NavigationPolicyFactory> navPolicyFactory =
0199 NavigationPolicyFactory{}
0200 .add<TryAllNavigationPolicy>(tryAllConfig)
0201 .asUniquePtr();
0202
0203 auto root = std::make_shared<TrackingVolume>(
0204 Transform3::Identity(), std::make_shared<CuboidVolumeBounds>(5., 5., 5.),
0205 "root");
0206 root->assignGeometryId(GeometryIdentifier{}.withVolume(1u));
0207 TrackingVolume* rootPtr = root.get();
0208 rootPtr->setNavigationPolicy(
0209 navPolicyFactory->build(gctx, *rootPtr, *logger));
0210
0211 Transform3 childTransform = Transform3::Identity();
0212 childTransform.pretranslate(Vector3{1., 0., 0.});
0213 auto child = std::make_unique<TrackingVolume>(
0214 childTransform, std::make_shared<CylinderVolumeBounds>(0.5, 1.0, 2.0),
0215 "child");
0216 child->assignGeometryId(GeometryIdentifier{}.withVolume(2u));
0217 TrackingVolume* childPtr = child.get();
0218 childPtr->setNavigationPolicy(
0219 navPolicyFactory->build(gctx, *childPtr, *logger));
0220 root->addVolume(std::move(child));
0221
0222 auto trivialBounds = std::make_shared<const RectangleBounds>(1., 1.);
0223 auto trivialSurface =
0224 Surface::makeShared<PlaneSurface>(Transform3::Identity(), trivialBounds);
0225 trivialSurface->assignGeometryId(
0226 GeometryIdentifier{}.withVolume(1u).withExtra(11u));
0227 auto trivialLink =
0228 std::make_unique<TrivialPortalLink>(trivialSurface, *childPtr);
0229 root->addPortal(std::make_shared<Portal>(Direction::AlongNormal(),
0230 std::move(trivialLink)));
0231
0232 auto compositeBounds = std::make_shared<const RectangleBounds>(1., 1.);
0233 Transform3 compositeTransformA = Transform3::Identity();
0234 compositeTransformA.pretranslate(Vector3{-1., 0., 0.});
0235 Transform3 compositeTransformB = Transform3::Identity();
0236 compositeTransformB.pretranslate(Vector3{1., 0., 0.});
0237 auto compositeSurfaceA =
0238 Surface::makeShared<PlaneSurface>(compositeTransformA, compositeBounds);
0239 auto compositeSurfaceB =
0240 Surface::makeShared<PlaneSurface>(compositeTransformB, compositeBounds);
0241 compositeSurfaceA->assignGeometryId(
0242 GeometryIdentifier{}.withVolume(1u).withExtra(12u));
0243 compositeSurfaceB->assignGeometryId(
0244 GeometryIdentifier{}.withVolume(1u).withExtra(13u));
0245 auto compositeLinkA =
0246 std::make_unique<TrivialPortalLink>(compositeSurfaceA, *childPtr);
0247 auto compositeLinkB =
0248 std::make_unique<TrivialPortalLink>(compositeSurfaceB, *rootPtr);
0249 auto compositeLink = std::make_unique<CompositePortalLink>(
0250 std::move(compositeLinkA), std::move(compositeLinkB),
0251 AxisDirection::AxisX);
0252 root->addPortal(std::make_shared<Portal>(Direction::AlongNormal(),
0253 std::move(compositeLink)));
0254
0255 auto gridBounds = std::make_shared<const RectangleBounds>(2., 1.);
0256 auto gridSurface =
0257 Surface::makeShared<PlaneSurface>(Transform3::Identity(), gridBounds);
0258 gridSurface->assignGeometryId(
0259 GeometryIdentifier{}.withVolume(1u).withExtra(14u));
0260 auto gridLink = GridPortalLink::make(gridSurface, AxisDirection::AxisX,
0261 Axis{AxisBound, -2., 2., 2});
0262 AnyGridView<const TrackingVolume*> gridView(gridLink->grid());
0263 gridView.atLocalBins({0u}) = rootPtr;
0264 gridView.atLocalBins({1u}) = childPtr;
0265 gridView.atLocalBins({2u}) = rootPtr;
0266 gridView.atLocalBins({3u}) = childPtr;
0267
0268 std::vector<TrivialPortalLink> artifacts;
0269 auto artifactSurface =
0270 Surface::makeShared<PlaneSurface>(Transform3::Identity(), gridBounds);
0271 artifactSurface->assignGeometryId(
0272 GeometryIdentifier{}.withVolume(1u).withExtra(15u));
0273 artifacts.emplace_back(artifactSurface, *childPtr);
0274 gridLink->setArtifactPortalLinks(std::move(artifacts));
0275
0276 root->addPortal(
0277 std::make_shared<Portal>(Direction::AlongNormal(), std::move(gridLink)));
0278
0279 auto sharedPortalBounds = std::make_shared<const RectangleBounds>(0.75, 0.75);
0280 auto sharedPortalSurface = Surface::makeShared<PlaneSurface>(
0281 Transform3::Identity(), sharedPortalBounds);
0282 sharedPortalSurface->assignGeometryId(
0283 GeometryIdentifier{}.withVolume(1u).withExtra(16u));
0284
0285 auto sharedPortal = std::make_shared<Portal>(
0286 gctx, std::make_unique<TrivialPortalLink>(sharedPortalSurface, *childPtr),
0287 std::make_unique<TrivialPortalLink>(sharedPortalSurface, *rootPtr));
0288 root->addPortal(sharedPortal);
0289 childPtr->addPortal(sharedPortal);
0290
0291 TrackingGeometryJsonConverter converter;
0292 nlohmann::json encoded = converter.trackingVolumeToJson(gctx, *root);
0293 TemporaryDirectory tmpDir{};
0294 auto jsonPath = tmpDir.path() / "tracking_geometry_roundtrip.json";
0295 {
0296 std::ofstream out(jsonPath);
0297 BOOST_REQUIRE(out.good());
0298 out << encoded.dump(2);
0299 }
0300
0301 nlohmann::json encodedFromFile;
0302 {
0303 std::ifstream in(jsonPath);
0304 BOOST_REQUIRE(in.good());
0305 in >> encodedFromFile;
0306 }
0307
0308 auto decodedRoot = converter.trackingVolumeFromJson(gctx, encodedFromFile);
0309
0310 BOOST_REQUIRE(decodedRoot != nullptr);
0311 BOOST_CHECK_EQUAL(decodedRoot->volumeName(), "root");
0312 BOOST_CHECK_EQUAL(decodedRoot->volumeBounds().type(), VolumeBounds::eCuboid);
0313
0314 std::vector<TrackingVolume*> decodedChildren;
0315 for (auto& decodedChild : decodedRoot->volumes()) {
0316 decodedChildren.push_back(&decodedChild);
0317 }
0318 BOOST_REQUIRE_EQUAL(decodedChildren.size(), 1u);
0319 BOOST_CHECK_EQUAL(decodedChildren.front()->volumeName(), "child");
0320 BOOST_CHECK_EQUAL(decodedChildren.front()->volumeBounds().type(),
0321 VolumeBounds::eCylinder);
0322
0323 std::vector<Portal*> decodedPortals;
0324 for (auto& portal : decodedRoot->portals()) {
0325 decodedPortals.push_back(&portal);
0326 }
0327 BOOST_REQUIRE_EQUAL(decodedPortals.size(), 4u);
0328
0329 const auto* decodedTrivial = dynamic_cast<const TrivialPortalLink*>(
0330 decodedPortals.at(0)->getLink(Direction::AlongNormal()));
0331 BOOST_REQUIRE(decodedTrivial != nullptr);
0332 BOOST_CHECK_EQUAL(decodedTrivial->volume().volumeName(), "child");
0333
0334 const auto* decodedComposite = dynamic_cast<const CompositePortalLink*>(
0335 decodedPortals.at(1)->getLink(Direction::AlongNormal()));
0336 BOOST_REQUIRE(decodedComposite != nullptr);
0337 BOOST_CHECK_EQUAL(decodedComposite->size(), 2u);
0338 BOOST_CHECK_EQUAL(decodedComposite->direction(), AxisDirection::AxisX);
0339
0340 const auto* decodedGrid = dynamic_cast<const GridPortalLink*>(
0341 decodedPortals.at(2)->getLink(Direction::AlongNormal()));
0342 BOOST_REQUIRE(decodedGrid != nullptr);
0343 BOOST_CHECK_EQUAL(decodedGrid->dim(), 1u);
0344 BOOST_CHECK_EQUAL(decodedGrid->artifactPortalLinks().size(), 1u);
0345
0346 AnyGridConstView<const TrackingVolume*> decodedGridView(decodedGrid->grid());
0347 BOOST_REQUIRE(decodedGridView.atLocalBins({0u}) != nullptr);
0348 BOOST_REQUIRE(decodedGridView.atLocalBins({1u}) != nullptr);
0349 BOOST_REQUIRE(decodedGridView.atLocalBins({2u}) != nullptr);
0350 BOOST_REQUIRE(decodedGridView.atLocalBins({3u}) != nullptr);
0351
0352 BOOST_CHECK_EQUAL(decodedGridView.atLocalBins({0u})->volumeName(), "root");
0353 BOOST_CHECK_EQUAL(decodedGridView.atLocalBins({1u})->volumeName(), "child");
0354 BOOST_CHECK_EQUAL(decodedGridView.atLocalBins({2u})->volumeName(), "root");
0355 BOOST_CHECK_EQUAL(decodedGridView.atLocalBins({3u})->volumeName(), "child");
0356
0357 std::vector<Portal*> decodedChildPortals;
0358 for (auto& portal : decodedChildren.front()->portals()) {
0359 decodedChildPortals.push_back(&portal);
0360 }
0361 BOOST_REQUIRE_EQUAL(decodedChildPortals.size(), 1u);
0362
0363 bool sharedPortalPreserved = false;
0364 for (Portal* rootPortal : decodedPortals) {
0365 if (rootPortal == decodedChildPortals.front()) {
0366 sharedPortalPreserved = true;
0367 break;
0368 }
0369 }
0370 BOOST_CHECK(sharedPortalPreserved);
0371
0372 auto decodedGeometry = converter.fromJson(gctx, encodedFromFile);
0373 BOOST_REQUIRE(decodedGeometry != nullptr);
0374 BOOST_REQUIRE(decodedGeometry->highestTrackingVolume() != nullptr);
0375 BOOST_CHECK_EQUAL(decodedGeometry->highestTrackingVolume()->volumeName(),
0376 "root");
0377
0378 const auto* htvSource = root.get();
0379 const auto* htvDecoded = decodedGeometry->highestTrackingVolume();
0380 BOOST_CHECK(*root == *htvDecoded);
0381 checkHierarchy(gctx, htvSource->volumes(), htvDecoded->volumes());
0382 }
0383
0384 BOOST_AUTO_TEST_CASE(TrackingGeometryJsonConverterNavigation) {
0385 GeometryContext gctx = GeometryContext::dangerouslyDefaultConstruct();
0386 MagneticFieldContext mctx;
0387
0388 auto field = std::make_shared<ConstantBField>(Vector3{0, 0, 0_T});
0389 EigenStepper<> stepper{field};
0390
0391 BoundTrackParameters start = BoundTrackParameters::createCurvilinear(
0392 Vector4::Zero(), Vector3::UnitX(), 1. / 1_GeV, std::nullopt,
0393 ParticleHypothesis::pion());
0394
0395
0396 using EndOfWorld = EndOfWorldReached;
0397 using ReferenceActorList = ActorList<StateCollector<>, EndOfWorld>;
0398 using PropagatorOptions =
0399 typename ConstantFieldPropagator::template Options<ReferenceActorList>;
0400
0401
0402 PropagatorOptions options(gctx, mctx);
0403
0404
0405 CylindricalTrackingGeometry cylindricalGeometryBuilder(gctx, true);
0406 auto sourceGeometry = cylindricalGeometryBuilder();
0407
0408 TrackingGeometryJsonConverter converter;
0409 nlohmann::json encoded = converter.toJson(gctx, *sourceGeometry);
0410
0411 auto jsonPath = "tracking_geometry_roundtrip.json";
0412 {
0413 std::ofstream out(jsonPath);
0414 BOOST_REQUIRE(out.good());
0415 out << encoded.dump(2);
0416 }
0417
0418 nlohmann::json encodedFromFile;
0419 {
0420 std::ifstream in(jsonPath);
0421 BOOST_REQUIRE(in.good());
0422 in >> encodedFromFile;
0423 }
0424
0425 auto decodedGeometry = converter.fromJson(gctx, encodedFromFile);
0426
0427 const auto* htvSource = sourceGeometry->highestTrackingVolume();
0428 const auto* htvDecoded = decodedGeometry->highestTrackingVolume();
0429 BOOST_CHECK(*htvSource == *htvDecoded);
0430
0431 checkHierarchy(gctx, htvSource->volumes(), htvDecoded->volumes());
0432
0433
0434
0435 Navigator::Config sourceNavCfg;
0436 sourceNavCfg.trackingGeometry =
0437 std::make_shared<TrackingGeometry>(*sourceGeometry);
0438 sourceNavCfg.resolveSensitive = true;
0439 sourceNavCfg.resolveMaterial = true;
0440 sourceNavCfg.resolvePassive = false;
0441 Navigator sourceNavigator{
0442 sourceNavCfg,
0443 Acts::getDefaultLogger("SourceNavigator", Acts::Logging::INFO)};
0444 ConstantFieldPropagator sourcePropagator(stepper, sourceNavigator);
0445
0446 auto sourceRes = sourcePropagator.propagate(start, options).value();
0447
0448 Navigator::Config decodedNavCfg;
0449 decodedNavCfg.trackingGeometry =
0450 std::make_shared<TrackingGeometry>(*decodedGeometry);
0451 decodedNavCfg.resolveSensitive = true;
0452 decodedNavCfg.resolveMaterial = true;
0453 decodedNavCfg.resolvePassive = false;
0454 Navigator decodedNavigator{
0455 sourceNavCfg,
0456 Acts::getDefaultLogger("DecodedNavigator", Acts::Logging::INFO)};
0457 ConstantFieldPropagator decodedPropagator(stepper, decodedNavigator);
0458
0459 auto decodedRes = decodedPropagator.propagate(start, options).value();
0460
0461 auto& sourceStates = sourceRes.template get<StateCollector<>::result_type>();
0462 auto& decodedStates =
0463 decodedRes.template get<StateCollector<>::result_type>();
0464 for (std::size_t i = 0; i < sourceStates.navigation.size(); i++) {
0465 auto& navigationA = sourceStates.navigation.at(i);
0466 auto& navigationB = decodedStates.navigation.at(i);
0467 if (!navigationA.navigationBreak) {
0468 BOOST_CHECK(*navigationA.currentVolume == *navigationB.currentVolume);
0469 BOOST_CHECK(*navigationA.startVolume == *navigationB.startVolume);
0470 BOOST_CHECK(*navigationA.currentSurface == *navigationB.currentSurface);
0471 BOOST_CHECK(*navigationA.startSurface == *navigationB.startSurface);
0472 } else {
0473 BOOST_CHECK_EQUAL(navigationA.currentVolume, nullptr);
0474 BOOST_CHECK_EQUAL(navigationB.currentVolume, nullptr);
0475 }
0476
0477 auto& steppingA = sourceStates.stepping.at(i);
0478 auto& steppingB = decodedStates.stepping.at(i);
0479 BOOST_CHECK(steppingA.pars == steppingB.pars);
0480 BOOST_CHECK(steppingA.nSteps == steppingB.nSteps);
0481 BOOST_CHECK(steppingA.pathAccumulated == steppingB.pathAccumulated);
0482 }
0483 }
0484
0485 BOOST_AUTO_TEST_SUITE_END()
0486
0487 BOOST_AUTO_TEST_SUITE(MultiLayerNavigationPolicySuite)
0488
0489 namespace {
0490
0491 auto makeMultiLayerVolume() {
0492 auto tVolume = std::make_shared<TrackingVolume>(
0493 Transform3::Identity(),
0494 std::make_shared<CuboidVolumeBounds>(20., 20., 5.), "CuboidVolume");
0495
0496 auto boundsRect = std::make_shared<Acts::RectangleBounds>(2., 2.);
0497 for (int ix = -1; ix <= 1; ++ix) {
0498 for (int iy = -1; iy <= 1; ++iy) {
0499 Transform3 trf = Transform3::Identity();
0500 trf.translation() = Acts::Vector3(4. * ix, 4. * iy, 0.);
0501 auto surface =
0502 Acts::Surface::makeShared<Acts::PlaneSurface>(trf, boundsRect);
0503 surface->assignIsSensitive(true);
0504 tVolume->addSurface(surface);
0505 }
0506 }
0507 return tVolume;
0508 }
0509
0510 auto makeMultiLayerPolicy(const GeometryContext& gctx,
0511 const TrackingVolume& volume, const Logger& logger) {
0512 Acts::Axis<AxisType::Equidistant, AxisBoundaryType::Bound> axisX(-10., 10.,
0513 5);
0514 Acts::Axis<AxisType::Equidistant, AxisBoundaryType::Bound> axisY(-10., 10.,
0515 5);
0516 Acts::Grid gridXY(Acts::Type<std::vector<std::size_t>>, std::move(axisX),
0517 std::move(axisY));
0518
0519 Experimental::MultiLayerNavigationPolicy::IndexedUpdatorType indexedGrid(
0520 std::move(gridXY), {AxisX, AxisY});
0521
0522 Experimental::MultiLayerNavigationPolicy::Config cfg;
0523 cfg.binExpansion = {1u, 1u};
0524 return Experimental::MultiLayerNavigationPolicy(gctx, volume, logger, cfg,
0525 std::move(indexedGrid));
0526 }
0527
0528 }
0529
0530 BOOST_AUTO_TEST_CASE(MultiLayerNavigationPolicyToJson) {
0531 auto tContext = GeometryContext::dangerouslyDefaultConstruct();
0532 auto tLogger =
0533 Acts::getDefaultLogger("MultiLayerNavigationJsonTest", Logging::INFO);
0534
0535 auto tVolume = makeMultiLayerVolume();
0536 auto policy = makeMultiLayerPolicy(tContext, *tVolume, *tLogger);
0537
0538 TrackingGeometryJsonConverter conv;
0539 nlohmann::json j = conv.navigationPolicyToJson(policy);
0540
0541 BOOST_CHECK(j.contains("kind"));
0542 BOOST_CHECK(j.contains("axes"));
0543 BOOST_CHECK(j.contains("casts"));
0544 BOOST_CHECK(j.contains("binExpansion"));
0545 BOOST_CHECK_EQUAL(j["kind"], "MultiLayerNavigation");
0546 BOOST_CHECK_EQUAL(j["axes"].size(), 2u);
0547 BOOST_CHECK_EQUAL(j["casts"].size(), 2u);
0548 BOOST_CHECK(!j.contains("surfaces"));
0549 }
0550
0551 BOOST_AUTO_TEST_CASE(MultiLayerNavigationPolicyRoundTrip) {
0552 auto tContext = GeometryContext::dangerouslyDefaultConstruct();
0553 auto tLogger =
0554 Acts::getDefaultLogger("MultiLayerNavigationJsonTest", Logging::INFO);
0555
0556 auto tVolume = makeMultiLayerVolume();
0557 auto policy = makeMultiLayerPolicy(tContext, *tVolume, *tLogger);
0558
0559 TrackingGeometryJsonConverter conv;
0560 nlohmann::json j = conv.navigationPolicyToJson(policy);
0561
0562 auto policyPtr =
0563 conv.navigationPolicyFromJson(tContext, j, *tVolume, *tLogger);
0564 auto& restored =
0565 dynamic_cast<Experimental::MultiLayerNavigationPolicy&>(*policyPtr);
0566
0567 const auto& origGrid = policy.indexedGrid().grid;
0568 const auto& restGrid = restored.indexedGrid().grid;
0569 BOOST_CHECK_EQUAL(origGrid.axes()[0]->getNBins(),
0570 restGrid.axes()[0]->getNBins());
0571 BOOST_CHECK_EQUAL(origGrid.axes()[1]->getNBins(),
0572 restGrid.axes()[1]->getNBins());
0573 BOOST_CHECK_CLOSE(origGrid.axes()[0]->getMin(), restGrid.axes()[0]->getMin(),
0574 1e-6);
0575 BOOST_CHECK_CLOSE(origGrid.axes()[0]->getMax(), restGrid.axes()[0]->getMax(),
0576 1e-6);
0577
0578 BOOST_CHECK_EQUAL(policy.indexedGrid().casts[0],
0579 restored.indexedGrid().casts[0]);
0580 BOOST_CHECK_EQUAL(policy.indexedGrid().casts[1],
0581 restored.indexedGrid().casts[1]);
0582
0583 BOOST_CHECK(policy.config().binExpansion == restored.config().binExpansion);
0584 }
0585
0586 BOOST_AUTO_TEST_SUITE_END()
0587
0588 }