File indexing completed on 2025-08-06 08:11:26
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/data/test_case.hpp>
0010 #include <boost/test/tools/output_test_stream.hpp>
0011 #include <boost/test/unit_test.hpp>
0012
0013 #include "Acts/Definitions/Algebra.hpp"
0014 #include "Acts/Definitions/Direction.hpp"
0015 #include "Acts/Definitions/Units.hpp"
0016 #include "Acts/EventData/GenericCurvilinearTrackParameters.hpp"
0017 #include "Acts/EventData/ParticleHypothesis.hpp"
0018 #include "Acts/EventData/TrackParameters.hpp"
0019 #include "Acts/Geometry/GeometryContext.hpp"
0020 #include "Acts/MagneticField/ConstantBField.hpp"
0021 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0022 #include "Acts/Propagator/AbortList.hpp"
0023 #include "Acts/Propagator/ActionList.hpp"
0024 #include "Acts/Propagator/EigenStepper.hpp"
0025 #include "Acts/Propagator/Propagator.hpp"
0026 #include "Acts/Propagator/StandardAborters.hpp"
0027 #include "Acts/Propagator/detail/LoopProtection.hpp"
0028 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0029 #include "Acts/Utilities/Logger.hpp"
0030 #include "Acts/Utilities/Result.hpp"
0031
0032 #include <algorithm>
0033 #include <array>
0034 #include <cmath>
0035 #include <limits>
0036 #include <memory>
0037 #include <optional>
0038 #include <random>
0039 #include <string>
0040 #include <tuple>
0041 #include <utility>
0042
0043 namespace bdata = boost::unit_test::data;
0044 using namespace Acts::UnitLiterals;
0045
0046 namespace Acts {
0047
0048 using namespace detail;
0049
0050 namespace Test {
0051
0052
0053 GeometryContext tgContext = GeometryContext();
0054 MagneticFieldContext mfContext = MagneticFieldContext();
0055
0056
0057 struct SteppingState {
0058
0059 Vector3 pos = Vector3(0., 0., 0.);
0060 Vector3 dir = Vector3(0., 0., 1);
0061 double p = 100_MeV;
0062 };
0063
0064
0065 struct Stepper {
0066 Vector3 field = Vector3(0., 0., 2_T);
0067
0068
0069
0070
0071
0072
0073
0074
0075 Result<Vector3> getField(SteppingState& ,
0076 const Vector3& ) const {
0077
0078 return Result<Vector3>::success(field);
0079 }
0080
0081
0082 Vector3 position(const SteppingState& state) const { return state.pos; }
0083
0084
0085 Vector3 direction(const SteppingState& state) const { return state.dir; }
0086
0087
0088 double absoluteMomentum(const SteppingState& state) const { return state.p; }
0089 };
0090
0091
0092 struct NavigationState {
0093 bool navigationBreak = false;
0094 };
0095
0096
0097 struct Options {
0098
0099 double pathLimit = std::numeric_limits<double>::max();
0100 bool loopProtection = true;
0101 double loopFraction = 0.5;
0102 Direction direction = Direction::Forward;
0103
0104 bool debug = false;
0105 std::string debugString;
0106 int debugMsgWidth = 60;
0107 int debugPfxWidth = 30;
0108
0109
0110 AbortList<PathLimitReached> abortList;
0111
0112 const Acts::Logger& logger = Acts::getDummyLogger();
0113 };
0114
0115
0116 struct PropagatorState {
0117
0118 SteppingState stepping;
0119
0120 NavigationState navigation;
0121
0122 Options options;
0123 };
0124
0125
0126
0127 BOOST_DATA_TEST_CASE(
0128 loop_aborter_test,
0129 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 21,
0130 bdata::distribution =
0131 std::uniform_real_distribution<double>(-M_PI, M_PI))) ^
0132 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 22,
0133 bdata::distribution =
0134 std::uniform_real_distribution<double>(-M_PI,
0135 M_PI))) ^
0136 bdata::xrange(1),
0137 phi, deltaPhi, index) {
0138 (void)index;
0139 (void)deltaPhi;
0140
0141 PropagatorState pState;
0142 pState.stepping.dir = Vector3(cos(phi), sin(phi), 0.);
0143 pState.stepping.p = 100_MeV;
0144
0145 Stepper pStepper;
0146
0147 auto& pathLimit = pState.options.abortList.get<PathLimitReached>();
0148 auto initialLimit = pathLimit.internalLimit;
0149
0150 detail::setupLoopProtection(
0151 pState, pStepper, pathLimit, false,
0152 *Acts::getDefaultLogger("LoopProt", Logging::INFO));
0153
0154 auto updatedLimit =
0155 pState.options.abortList.get<PathLimitReached>().internalLimit;
0156 BOOST_CHECK_LT(updatedLimit, initialLimit);
0157 }
0158
0159 using BField = ConstantBField;
0160 using EigenStepper = Acts::EigenStepper<>;
0161 using EigenPropagator = Propagator<EigenStepper>;
0162
0163 const int ntests = 100;
0164 const int skip = 0;
0165
0166
0167
0168 BOOST_DATA_TEST_CASE(
0169 propagator_loop_protection_test,
0170 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 20,
0171 bdata::distribution = std::uniform_real_distribution<double>(
0172 0.5_GeV, 10_GeV))) ^
0173 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 21,
0174 bdata::distribution =
0175 std::uniform_real_distribution<double>(-M_PI,
0176 M_PI))) ^
0177 bdata::random(
0178 (bdata::engine = std::mt19937(), bdata::seed = 22,
0179 bdata::distribution =
0180 std::uniform_real_distribution<double>(1.0, M_PI - 1.0))) ^
0181 bdata::random((bdata::engine = std::mt19937(), bdata::seed = 23,
0182 bdata::distribution =
0183 std::uniform_int_distribution<std::uint8_t>(0, 1))) ^
0184 bdata::xrange(ntests),
0185 pT, phi, theta, charge, index) {
0186 if (index < skip) {
0187 return;
0188 }
0189
0190 double px = pT * cos(phi);
0191 double py = pT * sin(phi);
0192 double pz = pT / tan(theta);
0193 double p = pT / sin(theta);
0194 double q = -1 + 2 * charge;
0195
0196 const double Bz = 2_T;
0197 auto bField = std::make_shared<BField>(Vector3{0, 0, Bz});
0198 EigenStepper estepper(bField);
0199 EigenPropagator epropagator(std::move(estepper));
0200
0201
0202 CurvilinearTrackParameters start(Vector4(0, 0, 0, 42), phi, theta, q / p,
0203 std::nullopt, ParticleHypothesis::pion());
0204
0205 using PropagatorOptions = PropagatorOptions<ActionList<>, AbortList<>>;
0206 PropagatorOptions options(tgContext, mfContext);
0207 options.maxSteps = 1e6;
0208 const auto& result = epropagator.propagate(start, options).value();
0209
0210
0211 CHECK_CLOSE_REL(px, -result.endParameters->momentum().x(), 1e-2);
0212 CHECK_CLOSE_REL(py, -result.endParameters->momentum().y(), 1e-2);
0213 CHECK_CLOSE_REL(pz, result.endParameters->momentum().z(), 1e-2);
0214 }
0215
0216 }
0217 }