File indexing completed on 2026-07-30 08:18:46
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/Geometry/GeometryContext.hpp"
0015 #include "Acts/MagneticField/ConstantBField.hpp"
0016 #include "Acts/Propagator/EigenStepper.hpp"
0017 #include "Acts/Propagator/Navigator.hpp"
0018 #include "Acts/Propagator/Propagator.hpp"
0019 #include "Acts/Propagator/StraightLineStepper.hpp"
0020 #include "Acts/Propagator/SurfaceCollector.hpp"
0021 #include "Acts/Propagator/TryAllNavigator.hpp"
0022 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0023 #include "Acts/Utilities/Logger.hpp"
0024 #include "Acts/Utilities/VectorHelpers.hpp"
0025 #include "ActsTests/CommonHelpers/CylindricalTrackingGeometry.hpp"
0026
0027 #include <algorithm>
0028 #include <numbers>
0029
0030 namespace bdata = boost::unit_test::data;
0031
0032 using namespace Acts;
0033 using namespace Acts::UnitLiterals;
0034 using Acts::VectorHelpers::perp;
0035
0036 namespace ActsTests {
0037
0038
0039 GeometryContext tgContext = GeometryContext::dangerouslyDefaultConstruct();
0040 MagneticFieldContext mfContext = MagneticFieldContext();
0041
0042 ActsTests::CylindricalTrackingGeometry cGeometry(tgContext);
0043 auto tGeometry = cGeometry();
0044
0045 const double Bz = 2_T;
0046 auto bField = std::make_shared<ConstantBField>(Vector3{0, 0, Bz});
0047
0048 using TestSurfaceCollector = SurfaceCollector<SurfaceSelector>;
0049 using ParamRecorder = BoundParameterRecorder<SurfaceSelector>;
0050
0051 std::vector<GeometryIdentifier> collectRelevantGeoIds(
0052 const TestSurfaceCollector::result_type& surfaceHits) {
0053 std::vector<GeometryIdentifier> geoIds;
0054 for (const auto& surfaceHit : surfaceHits.collected) {
0055 auto geoId = surfaceHit.surface->geometryId();
0056 auto material = surfaceHit.surface->surfaceMaterial();
0057 if (geoId.sensitive() == 0 && material == nullptr) {
0058 continue;
0059 }
0060 geoIds.push_back(geoId);
0061 }
0062 return geoIds;
0063 }
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073 template <typename propagator_t>
0074 void runSelfConsistencyTest(const propagator_t& prop,
0075 const BoundTrackParameters& start,
0076 const Logger& logger) {
0077
0078 using ActorList = ActorList<TestSurfaceCollector, ParamRecorder>;
0079 using Options = typename propagator_t::template Options<ActorList>;
0080
0081
0082 Options fwdOptions(tgContext, mfContext);
0083 fwdOptions.pathLimit = 25_cm;
0084
0085
0086 auto& fwdSurfaceCollector =
0087 fwdOptions.actorList.template get<TestSurfaceCollector>();
0088 fwdSurfaceCollector.selector.selectSensitive = true;
0089 fwdSurfaceCollector.selector.selectMaterial = true;
0090 fwdSurfaceCollector.selector.selectPassive = true;
0091
0092 auto& paramRecorder = fwdOptions.actorList.template get<ParamRecorder>();
0093 paramRecorder.selector.selectSensitive = true;
0094 paramRecorder.selector.selectMaterial = true;
0095 paramRecorder.selector.selectPassive = true;
0096
0097 ACTS_DEBUG(">>> Forward Propagation : start.");
0098 auto fwdResult = prop.propagate(start, fwdOptions).value();
0099 auto fwdSurfaceHits =
0100 fwdResult.template get<TestSurfaceCollector::result_type>().collected;
0101
0102 auto fwdTrackRecords = fwdResult.template get<ParamRecorder::result_type>();
0103
0104 BOOST_CHECK_EQUAL(fwdTrackRecords.size(), fwdSurfaceHits.size());
0105 for (const auto& boundPars :
0106 fwdResult.template get<ParamRecorder::result_type>()) {
0107 BOOST_CHECK_EQUAL(boundPars.particleHypothesis(),
0108 start.particleHypothesis());
0109 BOOST_CHECK_EQUAL(boundPars.covariance().has_value(),
0110 start.covariance().has_value());
0111 BOOST_CHECK_EQUAL(
0112 std::ranges::any_of(
0113 fwdSurfaceHits,
0114 [&](const Acts::SurfaceHit& hit) {
0115 return hit.surface ==
0116 boundPars.referenceSurface().getSharedPtr().get();
0117 }),
0118 true);
0119 }
0120
0121 auto fwdSurfaces = collectRelevantGeoIds(
0122 fwdResult.template get<TestSurfaceCollector::result_type>());
0123
0124 ACTS_DEBUG(">>> Surface hits found on ...");
0125 for (const auto& fwdSteps : fwdSurfaces) {
0126 ACTS_DEBUG("--> Surface with " << fwdSteps);
0127 }
0128 ACTS_DEBUG(">>> Forward Propagation : end.");
0129
0130
0131 Options bwdOptions(tgContext, mfContext);
0132 bwdOptions.pathLimit = 25_cm;
0133 bwdOptions.direction = Direction::Backward();
0134
0135
0136 auto& bwdMSurfaceCollector =
0137 bwdOptions.actorList.template get<TestSurfaceCollector>();
0138 bwdMSurfaceCollector.selector.selectSensitive = true;
0139 bwdMSurfaceCollector.selector.selectMaterial = true;
0140 bwdMSurfaceCollector.selector.selectPassive = true;
0141
0142 const auto& startSurface = start.referenceSurface();
0143
0144 ACTS_DEBUG(">>> Backward Propagation : start.");
0145 auto bwdResult =
0146 prop.propagate(*fwdResult.endParameters, startSurface, bwdOptions)
0147 .value();
0148 auto bwdSurfaceHits =
0149 bwdResult.template get<TestSurfaceCollector::result_type>().collected;
0150 auto bwdSurfaces = collectRelevantGeoIds(
0151 bwdResult.template get<TestSurfaceCollector::result_type>());
0152
0153 ACTS_DEBUG(">>> Surface hits found on ...");
0154 for (auto& bwdSteps : bwdSurfaces) {
0155 ACTS_DEBUG("--> Surface with " << bwdSteps);
0156 }
0157 ACTS_DEBUG(">>> Backward Propagation : end.");
0158
0159
0160 {
0161 std::ranges::reverse(bwdSurfaces);
0162 BOOST_CHECK_EQUAL_COLLECTIONS(bwdSurfaces.begin(), bwdSurfaces.end(),
0163 fwdSurfaces.begin(), fwdSurfaces.end());
0164 }
0165
0166
0167
0168 Options fwdStepOptions(tgContext, mfContext);
0169
0170
0171 auto& fwdStepSurfaceCollector =
0172 fwdOptions.actorList.template get<TestSurfaceCollector>();
0173 fwdStepSurfaceCollector.selector.selectSensitive = true;
0174 fwdStepSurfaceCollector.selector.selectMaterial = true;
0175 fwdStepSurfaceCollector.selector.selectPassive = true;
0176
0177 std::vector<GeometryIdentifier> fwdStepSurfaces;
0178
0179
0180 BoundTrackParameters sParameters = start;
0181 std::vector<BoundTrackParameters> stepParameters;
0182 for (auto& fwdSteps : fwdSurfaceHits) {
0183 ACTS_DEBUG(">>> Forward step : "
0184 << sParameters.referenceSurface().geometryId() << " --> "
0185 << fwdSteps.surface->geometryId());
0186
0187
0188 auto fwdStep =
0189 prop.propagate(sParameters, *fwdSteps.surface, fwdStepOptions).value();
0190
0191 auto fwdStepSurfacesTmp = collectRelevantGeoIds(
0192 fwdStep.template get<TestSurfaceCollector::result_type>());
0193 fwdStepSurfaces.insert(fwdStepSurfaces.end(), fwdStepSurfacesTmp.begin(),
0194 fwdStepSurfacesTmp.end());
0195
0196 if (fwdStep.endParameters.has_value()) {
0197
0198 stepParameters.push_back(*fwdStep.endParameters);
0199 sParameters = stepParameters.back();
0200 }
0201 }
0202
0203 const Surface& dSurface = fwdResult.endParameters->referenceSurface();
0204 ACTS_DEBUG(">>> Forward step : "
0205 << sParameters.referenceSurface().geometryId() << " --> "
0206 << dSurface.geometryId());
0207 auto fwdStepFinal =
0208 prop.propagate(sParameters, dSurface, fwdStepOptions).value();
0209 auto fwdStepSurfacesTmp = collectRelevantGeoIds(
0210 fwdStepFinal.template get<TestSurfaceCollector::result_type>());
0211 fwdStepSurfaces.insert(fwdStepSurfaces.end(), fwdStepSurfacesTmp.begin(),
0212 fwdStepSurfacesTmp.end());
0213
0214
0215
0216
0217
0218 Options bwdStepOptions(tgContext, mfContext);
0219 bwdStepOptions.direction = Direction::Backward();
0220
0221
0222 auto& bwdStepSurfaceCollector =
0223 bwdOptions.actorList.template get<TestSurfaceCollector>();
0224 bwdStepSurfaceCollector.selector.selectSensitive = true;
0225 bwdStepSurfaceCollector.selector.selectMaterial = true;
0226 bwdStepSurfaceCollector.selector.selectPassive = true;
0227
0228 std::vector<GeometryIdentifier> bwdStepSurfaces;
0229
0230
0231 sParameters = *fwdResult.endParameters;
0232 for (auto& bwdSteps : bwdSurfaceHits) {
0233 ACTS_DEBUG(">>> Backward step : "
0234 << sParameters.referenceSurface().geometryId() << " --> "
0235 << bwdSteps.surface->geometryId());
0236
0237
0238 auto bwdStep =
0239 prop.propagate(sParameters, *bwdSteps.surface, bwdStepOptions).value();
0240
0241 auto bwdStepSurfacesTmp = collectRelevantGeoIds(
0242 bwdStep.template get<TestSurfaceCollector::result_type>());
0243 bwdStepSurfaces.insert(bwdStepSurfaces.end(), bwdStepSurfacesTmp.begin(),
0244 bwdStepSurfacesTmp.end());
0245
0246 if (bwdStep.endParameters.has_value()) {
0247
0248 stepParameters.push_back(*bwdStep.endParameters);
0249 sParameters = stepParameters.back();
0250 }
0251 }
0252
0253 const Surface& dbSurface = start.referenceSurface();
0254 ACTS_DEBUG(">>> Backward step : "
0255 << sParameters.referenceSurface().geometryId() << " --> "
0256 << dSurface.geometryId());
0257 auto bwdStepFinal =
0258 prop.propagate(sParameters, dbSurface, bwdStepOptions).value();
0259 auto bwdStepSurfacesTmp = collectRelevantGeoIds(
0260 bwdStepFinal.template get<TestSurfaceCollector::result_type>());
0261 bwdStepSurfaces.insert(bwdStepSurfaces.end(), bwdStepSurfacesTmp.begin(),
0262 bwdStepSurfacesTmp.end());
0263
0264
0265
0266 std::ranges::reverse(bwdStepSurfaces);
0267 BOOST_CHECK_EQUAL_COLLECTIONS(bwdStepSurfaces.begin(), bwdStepSurfaces.end(),
0268 fwdStepSurfaces.begin(), fwdStepSurfaces.end());
0269 }
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281 template <typename propagator_probe_t, typename propagator_ref_t>
0282 void runConsistencyTest(const propagator_probe_t& propProbe,
0283 const propagator_ref_t& propRef,
0284 const BoundTrackParameters& start,
0285 const Logger& logger) {
0286
0287 using ActorList = ActorList<TestSurfaceCollector>;
0288
0289 auto run = [&](const auto& prop) {
0290 using propagator_t = std::decay_t<decltype(prop)>;
0291 using Options = typename propagator_t::template Options<ActorList>;
0292
0293
0294 Options fwdOptions(tgContext, mfContext);
0295 fwdOptions.pathLimit = 25_cm;
0296 fwdOptions.stepping.maxStepSize = 1_cm;
0297
0298
0299 auto& fwdSurfaceCollector =
0300 fwdOptions.actorList.template get<TestSurfaceCollector>();
0301 fwdSurfaceCollector.selector.selectSensitive = true;
0302 fwdSurfaceCollector.selector.selectMaterial = true;
0303 fwdSurfaceCollector.selector.selectPassive = true;
0304
0305 auto fwdResult = prop.propagate(start, fwdOptions).value();
0306 auto fwdSurfaces = collectRelevantGeoIds(
0307 fwdResult.template get<TestSurfaceCollector::result_type>());
0308
0309 ACTS_DEBUG(">>> Surface hits found on ...");
0310 for (const auto& fwdSteps : fwdSurfaces) {
0311 ACTS_DEBUG("--> Surface with " << fwdSteps);
0312 }
0313
0314 return fwdSurfaces;
0315 };
0316
0317 ACTS_DEBUG(">>> Probe Propagation : start.");
0318 const auto& probeSurfaces = run(propProbe);
0319 ACTS_DEBUG(">>> Probe Propagation : end.");
0320
0321 ACTS_DEBUG(">>> Reference Propagation : start.");
0322 const auto& refSurfaces = run(propRef);
0323 ACTS_DEBUG(">>> Reference Propagation : end.");
0324
0325
0326 BOOST_CHECK_EQUAL_COLLECTIONS(probeSurfaces.begin(), probeSurfaces.end(),
0327 refSurfaces.begin(), refSurfaces.end());
0328 }
0329
0330 Logging::Level logLevel = Logging::INFO;
0331
0332 const int nTestsSelfConsistency = 500;
0333 const int nTestsRefConsistency = 500;
0334
0335 using StraightLinePropagator = Propagator<StraightLineStepper, Navigator>;
0336 using TestEigenStepper = EigenStepper<>;
0337 using EigenPropagator = Propagator<TestEigenStepper, Navigator>;
0338 using ReferenceStraightLinePropagator =
0339 Propagator<StraightLineStepper, Experimental::TryAllNavigator>;
0340 using ReferenceEigenPropagator =
0341 Propagator<TestEigenStepper, Experimental::TryAllNavigator>;
0342
0343 StraightLineStepper slstepper;
0344 TestEigenStepper estepper(bField);
0345
0346 StraightLinePropagator slpropagator(slstepper,
0347 Navigator({tGeometry, true, true, false},
0348 getDefaultLogger("sl_nav",
0349 Logging::INFO)),
0350 getDefaultLogger("sl_prop", Logging::INFO));
0351 EigenPropagator epropagator(estepper,
0352 Navigator({tGeometry, true, true, false},
0353 getDefaultLogger("e_nav", Logging::INFO)),
0354 getDefaultLogger("e_prop", Logging::INFO));
0355
0356 ReferenceStraightLinePropagator refslpropagator(
0357 slstepper,
0358 Experimental::TryAllNavigator({tGeometry, true, true, false},
0359 getDefaultLogger("ref_sl_nav",
0360 Logging::INFO)),
0361 getDefaultLogger("ref_sl_prop", Logging::INFO));
0362 ReferenceEigenPropagator refepropagator(
0363 estepper,
0364 Experimental::TryAllNavigator({tGeometry, true, true, false,
0365 BoundaryTolerance::Infinite()},
0366 getDefaultLogger("ref_e_nav", Logging::INFO)),
0367 getDefaultLogger("ref_e_prop", Logging::INFO));
0368
0369 auto eventGen =
0370 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 20,
0371 bdata::distribution = std::uniform_real_distribution<double>(
0372 0.5_GeV, 10_GeV))) ^
0373 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 21,
0374 bdata::distribution = std::uniform_real_distribution<double>(
0375 -std::numbers::pi, std::numbers::pi))) ^
0376 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 22,
0377 bdata::distribution = std::uniform_real_distribution<double>(
0378 1., std::numbers::pi - 1.))) ^
0379 bdata::random(
0380 (bdata::engine = std::mt19937(), bdata::seed = 23,
0381 bdata::distribution = std::uniform_int_distribution<int>(0, 1)));
0382
0383 BoundTrackParameters createStartParameters(double pT, double phi, double theta,
0384 int charge) {
0385 double p = pT / std::sin(theta);
0386 double q = -1 + 2 * charge;
0387 return BoundTrackParameters::createCurvilinear(Vector4::Zero(), phi, theta,
0388 q / p, std::nullopt,
0389 ParticleHypothesis::pion());
0390 }
0391
0392 BOOST_DATA_TEST_CASE(NavigatorStraightLineSelfConsistency,
0393 eventGen ^ bdata::xrange(nTestsSelfConsistency), pT, phi,
0394 theta, charge, index) {
0395 ACTS_LOCAL_LOGGER(getDefaultLogger("NavigatorTest", logLevel));
0396
0397 BoundTrackParameters start = createStartParameters(pT, phi, theta, charge);
0398
0399 ACTS_DEBUG(">>> Run navigation tests with:\n pT = "
0400 << pT << "\n phi = " << phi << "\n theta = " << theta
0401 << "\n charge = " << charge << "\n index = " << index);
0402
0403 ACTS_DEBUG(">>> Test self consistency slpropagator");
0404 runSelfConsistencyTest(slpropagator, start, logger());
0405 }
0406
0407 BOOST_DATA_TEST_CASE(NavigatorEigenSelfConsistency,
0408 eventGen ^ bdata::xrange(nTestsSelfConsistency), pT, phi,
0409 theta, charge, index) {
0410 ACTS_LOCAL_LOGGER(getDefaultLogger("NavigatorTest", logLevel));
0411
0412 BoundTrackParameters start = createStartParameters(pT, phi, theta, charge);
0413
0414 ACTS_DEBUG(">>> Run navigation tests with:\n pT = "
0415 << pT << "\n phi = " << phi << "\n theta = " << theta
0416 << "\n charge = " << charge << "\n index = " << index);
0417
0418 ACTS_DEBUG(">>> Test self consistency epropagator");
0419 runSelfConsistencyTest(epropagator, start, logger());
0420 }
0421
0422 BOOST_DATA_TEST_CASE(NavigatorRefStraightLineConsistency,
0423 eventGen ^ bdata::xrange(nTestsRefConsistency), pT, phi,
0424 theta, charge, index) {
0425 ACTS_LOCAL_LOGGER(getDefaultLogger("NavigatorTest", logLevel));
0426
0427 BoundTrackParameters start = createStartParameters(pT, phi, theta, charge);
0428
0429 ACTS_DEBUG(">>> Run navigation tests with:\n pT = "
0430 << pT << "\n phi = " << phi << "\n theta = " << theta
0431 << "\n charge = " << charge << "\n index = " << index);
0432
0433 ACTS_DEBUG(">>> Test reference consistency slpropagator");
0434 runConsistencyTest(slpropagator, refslpropagator, start, logger());
0435 }
0436
0437 BOOST_DATA_TEST_CASE(NavigatorRefEigenConsistency,
0438 eventGen ^ bdata::xrange(nTestsRefConsistency), pT, phi,
0439 theta, charge, index) {
0440 ACTS_LOCAL_LOGGER(getDefaultLogger("NavigatorTest", logLevel));
0441
0442 BoundTrackParameters start = createStartParameters(pT, phi, theta, charge);
0443
0444 ACTS_DEBUG(">>> Run navigation tests with:\n pT = "
0445 << pT << "\n phi = " << phi << "\n theta = " << theta
0446 << "\n charge = " << charge << "\n index = " << index);
0447
0448 ACTS_DEBUG(">>> Test reference consistency epropagator");
0449 runConsistencyTest(epropagator, refepropagator, start, logger());
0450 }
0451
0452 }