File indexing completed on 2025-10-14 08:02:14
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/data/test_case.hpp>
0010 #include <boost/test/unit_test.hpp>
0011
0012 #include "Acts/Definitions/Algebra.hpp"
0013 #include "Acts/Definitions/Units.hpp"
0014 #include "Acts/EventData/TrackParameters.hpp"
0015 #include "Acts/Geometry/GeometryContext.hpp"
0016 #include "Acts/MagneticField/ConstantBField.hpp"
0017 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0018 #include "Acts/Propagator/ActorList.hpp"
0019 #include "Acts/Propagator/DirectNavigator.hpp"
0020 #include "Acts/Propagator/EigenStepper.hpp"
0021 #include "Acts/Propagator/MaterialInteractor.hpp"
0022 #include "Acts/Propagator/Navigator.hpp"
0023 #include "Acts/Propagator/Propagator.hpp"
0024 #include "Acts/Propagator/StandardAborters.hpp"
0025 #include "Acts/Propagator/StraightLineStepper.hpp"
0026 #include "Acts/Propagator/SurfaceCollector.hpp"
0027 #include "Acts/Surfaces/PlaneSurface.hpp"
0028 #include "ActsTests/CommonHelpers/CylindricalTrackingGeometry.hpp"
0029 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0030
0031 #include <cmath>
0032 #include <iostream>
0033 #include <memory>
0034 #include <numbers>
0035 #include <random>
0036 #include <utility>
0037 #include <vector>
0038
0039 namespace Acts {
0040 class Surface;
0041 }
0042
0043 namespace bdata = boost::unit_test::data;
0044
0045 using namespace Acts;
0046 using namespace Acts::UnitLiterals;
0047
0048 namespace ActsTests {
0049
0050
0051 GeometryContext tgContext = GeometryContext();
0052 MagneticFieldContext mfContext = MagneticFieldContext();
0053
0054 CylindricalTrackingGeometry cGeometry(tgContext);
0055 auto tGeometry = cGeometry();
0056
0057
0058 Navigator navigator({tGeometry});
0059 DirectNavigator dnavigator;
0060
0061 using BField = ConstantBField;
0062 using Stepper = EigenStepper<>;
0063 using ReferencePropagator = Propagator<Stepper, Navigator>;
0064 using DirectPropagator = Propagator<Stepper, DirectNavigator>;
0065
0066 const double Bz = 2_T;
0067 auto bField = std::make_shared<BField>(Vector3{0, 0, Bz});
0068 Stepper estepper(bField);
0069 Stepper dstepper(bField);
0070
0071 ReferencePropagator rpropagator(std::move(estepper), std::move(navigator));
0072 DirectPropagator dpropagator(std::move(dstepper), std::move(dnavigator));
0073
0074 const int ntests = 1000;
0075 const int skip = 0;
0076 bool referenceTiming = false;
0077 bool oversteppingTest = false;
0078 double oversteppingMaxStepSize = 1_mm;
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093 template <typename rpropagator_t, typename dpropagator_t>
0094 void runTest(const rpropagator_t& rprop, const dpropagator_t& dprop, double pT,
0095 double phi, double theta, int charge, int index) {
0096 double dcharge = -1 + 2 * charge;
0097
0098 if (index < skip) {
0099 return;
0100 }
0101
0102
0103 double p = pT / sin(theta);
0104 BoundTrackParameters start = BoundTrackParameters::createCurvilinear(
0105 Vector4::Zero(), phi, theta, dcharge / p, std::nullopt,
0106 ParticleHypothesis::pion());
0107
0108 using EndOfWorld = EndOfWorldReached;
0109
0110
0111 using ReferenceActorList =
0112 ActorList<MaterialInteractor, SurfaceCollector<>, EndOfWorld>;
0113
0114
0115 using Options = typename rpropagator_t::template Options<ReferenceActorList>;
0116 Options pOptions(tgContext, mfContext);
0117 if (oversteppingTest) {
0118 pOptions.stepping.maxStepSize = oversteppingMaxStepSize;
0119 }
0120
0121
0122 auto& sCollector = pOptions.actorList.template get<SurfaceCollector<>>();
0123 sCollector.selector.selectSensitive = true;
0124 sCollector.selector.selectMaterial = true;
0125
0126
0127 const auto& pResult = rprop.propagate(start, pOptions).value();
0128 auto& cSurfaces = pResult.template get<SurfaceCollector<>::result_type>();
0129 auto& cMaterial = pResult.template get<MaterialInteractor::result_type>();
0130 const Surface& destination = pResult.endParameters->referenceSurface();
0131
0132 std::cout << " - the standard navigator yielded "
0133 << cSurfaces.collected.size() << " collected surfaces" << std::endl;
0134
0135 if (!referenceTiming) {
0136
0137 std::vector<const Surface*> surfaceSequence;
0138 surfaceSequence.reserve(cSurfaces.collected.size());
0139 for (auto& cs : cSurfaces.collected) {
0140 surfaceSequence.push_back(cs.surface);
0141 }
0142
0143
0144 using DirectActorList = ActorList<MaterialInteractor, SurfaceCollector<>>;
0145
0146
0147 using DirectOptions =
0148 typename dpropagator_t::template Options<DirectActorList>;
0149 DirectOptions dOptions(tgContext, mfContext);
0150
0151 dOptions.navigation.surfaces = surfaceSequence;
0152
0153 auto& dCollector = dOptions.actorList.template get<SurfaceCollector<>>();
0154 dCollector.selector.selectSensitive = true;
0155 dCollector.selector.selectMaterial = true;
0156
0157
0158 const auto& ddResult =
0159 dprop.propagate(start, destination, dOptions).value();
0160 auto& ddSurfaces = ddResult.template get<SurfaceCollector<>::result_type>();
0161 auto& ddMaterial = ddResult.template get<MaterialInteractor::result_type>();
0162
0163
0164 BOOST_CHECK_EQUAL(cSurfaces.collected.size(), ddSurfaces.collected.size());
0165 CHECK_CLOSE_REL(cMaterial.materialInX0, ddMaterial.materialInX0, 1e-3);
0166
0167
0168 const auto& dwResult = dprop.propagate(start, dOptions).value();
0169 auto& dwSurfaces = dwResult.template get<SurfaceCollector<>::result_type>();
0170
0171
0172 BOOST_CHECK_EQUAL(cSurfaces.collected.size(), dwSurfaces.collected.size());
0173 }
0174 }
0175
0176
0177
0178 BOOST_DATA_TEST_CASE(
0179 test_direct_navigator,
0180 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 20,
0181 bdata::distribution = std::uniform_real_distribution<double>(
0182 0.15_GeV, 10_GeV))) ^
0183 bdata::random(
0184 (bdata::engine = std::mt19937(), bdata::seed = 21,
0185 bdata::distribution = std::uniform_real_distribution<double>(
0186 -std::numbers::pi, std::numbers::pi))) ^
0187 bdata::random(
0188 (bdata::engine = std::mt19937(), bdata::seed = 22,
0189 bdata::distribution = std::uniform_real_distribution<double>(
0190 1., std::numbers::pi - 1.))) ^
0191 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 23,
0192 bdata::distribution =
0193 std::uniform_int_distribution<std::uint8_t>(0, 1))) ^
0194 bdata::xrange(ntests),
0195 pT, phi, theta, charge, index) {
0196
0197 runTest(rpropagator, dpropagator, pT, phi, theta, charge, index);
0198 }
0199
0200 struct NavigationBreakAborter {
0201 bool checkAbort(const auto& state, const auto& , const auto& nav,
0202 const auto& ) const {
0203 return nav.navigationBreak(state.navigation);
0204 }
0205 };
0206
0207
0208
0209
0210 #if defined(__clang__) && __clang_major__ < 16
0211 #define CLANG_RANGE_BUG_WORKAROUND
0212 #endif
0213
0214 #ifdef CLANG_RANGE_BUG_WORKAROUND
0215 template <typename It>
0216 struct Subrange {
0217 It b, e;
0218 Subrange(It b_, It e_) : b(b_), e(e_) {}
0219 auto begin() const { return b; }
0220 auto end() const { return e; }
0221 };
0222 #endif
0223
0224
0225
0226 #ifdef CLANG_RANGE_BUG_WORKAROUND
0227 template <typename ref_surfaces_t>
0228 #else
0229 template <std::ranges::range ref_surfaces_t>
0230 #endif
0231 void runSimpleTest(const std::vector<const Surface*>& surfaces,
0232 Direction direction, const Surface* startSurface,
0233 ref_surfaces_t expectedSurfaces) {
0234 Propagator<StraightLineStepper, DirectNavigator> prop(StraightLineStepper{},
0235 DirectNavigator{});
0236
0237 using DirectActorList = ActorList<SurfaceCollector<>, NavigationBreakAborter>;
0238 using DirectOptions =
0239 typename Propagator<StraightLineStepper,
0240 DirectNavigator>::template Options<DirectActorList>;
0241 DirectOptions pOptions(tgContext, mfContext);
0242 pOptions.direction = direction;
0243 pOptions.navigation.surfaces = surfaces;
0244 pOptions.navigation.startSurface = startSurface;
0245 auto& dCollector = pOptions.actorList.template get<SurfaceCollector<>>();
0246 dCollector.selector.selectSensitive = true;
0247 dCollector.selector.selectMaterial = true;
0248 dCollector.selector.selectPassive = true;
0249
0250
0251 BoundTrackParameters startParameters = BoundTrackParameters(
0252 startSurface->getSharedPtr(),
0253 {0.0_mm, 0.0_mm, 0.0_rad, 0.0_rad, 1.0 / 1.0_GeV, 0.0_ns}, std::nullopt,
0254 ParticleHypothesis::muon());
0255
0256
0257 auto result = prop.propagate(startParameters, pOptions);
0258
0259
0260 BOOST_REQUIRE(result.ok());
0261
0262
0263 const auto& collectedSurfaceHits =
0264 result->get<SurfaceCollector<>::result_type>().collected;
0265 std::vector<const Surface*> collectedSurfaces;
0266 std::ranges::transform(collectedSurfaceHits,
0267 std::back_inserter(collectedSurfaces),
0268 [](const auto& hit) { return hit.surface; });
0269
0270 collectedSurfaces.erase(
0271 std::unique(collectedSurfaces.begin(), collectedSurfaces.end()),
0272 collectedSurfaces.end());
0273 BOOST_CHECK_EQUAL_COLLECTIONS(
0274 collectedSurfaces.begin(), collectedSurfaces.end(),
0275 expectedSurfaces.begin(), expectedSurfaces.end());
0276 }
0277
0278 BOOST_AUTO_TEST_SUITE(PropagatorSuite)
0279
0280 BOOST_AUTO_TEST_CASE(test_direct_navigator_fwd_bwd) {
0281
0282 std::vector<std::shared_ptr<const Surface>> surfaces;
0283 for (int i = 0; i < 10; i++) {
0284 Transform3 transform = Transform3::Identity();
0285 transform.translate(Vector3{0.0_mm, 0.0_mm, i * 100.0_mm});
0286 auto surface = Surface::makeShared<PlaneSurface>(transform, nullptr);
0287 surface->assignGeometryId(
0288 GeometryIdentifier().withVolume(1).withLayer(1).withSensitive(i + 1));
0289 surfaces.push_back(surface);
0290 }
0291
0292
0293 std::vector<const Surface*> surfacePointers;
0294 std::ranges::transform(surfaces, std::back_inserter(surfacePointers),
0295 [](const auto& s) { return s.get(); });
0296
0297 for (auto it = surfacePointers.begin(); it != surfacePointers.end(); ++it) {
0298 runSimpleTest(surfacePointers, Direction::Forward(), *it,
0299 #ifndef CLANG_RANGE_BUG_WORKAROUND
0300 std::ranges::subrange{it, surfacePointers.end()});
0301 #else
0302 Subrange{it, surfacePointers.end()});
0303 #endif
0304 }
0305 for (auto it = surfacePointers.rbegin(); it != surfacePointers.rend(); ++it) {
0306 runSimpleTest(surfacePointers, Direction::Backward(), *it,
0307 #ifndef CLANG_RANGE_BUG_WORKAROUND
0308 std::ranges::subrange{it, surfacePointers.rend()});
0309 #else
0310 Subrange{it, surfacePointers.rend()});
0311 #endif
0312 }
0313 }
0314
0315 BOOST_AUTO_TEST_SUITE_END()
0316
0317 }