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