Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-08 08:11:31

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
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/Tests/CommonHelpers/FloatComparisons.hpp"
0025 #include "Acts/Utilities/Logger.hpp"
0026 #include "Acts/Utilities/Result.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 using namespace Acts::UnitLiterals;
0038 using namespace Acts::detail;
0039 
0040 namespace Acts::Test {
0041 
0042 // Create a test context
0043 GeometryContext tgContext = GeometryContext();
0044 MagneticFieldContext mfContext = MagneticFieldContext();
0045 
0046 /// @brief mockup of stepping state
0047 struct SteppingState {
0048   /// Parameters
0049   Vector3 pos = Vector3(0., 0., 0.);
0050   Vector3 dir = Vector3(0., 0., 1);
0051   double p = 100_MeV;
0052 };
0053 
0054 /// @brief mockup of stepping state
0055 struct Stepper {
0056   Vector3 field = Vector3(0., 0., 2_T);
0057 
0058   /// Get the field for the stepping, it checks first if the access is still
0059   /// within the Cell, and updates the cell if necessary.
0060   ///
0061   /// @param [in,out] state is the propagation state associated with the track
0062   ///                 the magnetic field cell is used (and potentially
0063   ///                 updated)
0064   /// @param [in] pos is the field position
0065   Result<Vector3> getField(SteppingState& /*state*/,
0066                            const Vector3& /*pos*/) const {
0067     // get the field from the cell
0068     return Result<Vector3>::success(field);
0069   }
0070 
0071   /// Access method - position
0072   Vector3 position(const SteppingState& state) const { return state.pos; }
0073 
0074   /// Access method - direction
0075   Vector3 direction(const SteppingState& state) const { return state.dir; }
0076 
0077   /// Access method - momentum
0078   double absoluteMomentum(const SteppingState& state) const { return state.p; }
0079 };
0080 
0081 /// @brief mockup of navigation state
0082 struct NavigationState {
0083   bool navigationBreak = false;
0084 };
0085 
0086 /// @brief mockup of the Propagator Options
0087 struct Options {
0088   /// Absolute maximum path length
0089   double pathLimit = std::numeric_limits<double>::max();
0090   bool loopProtection = true;
0091   double loopFraction = 0.5;
0092   Direction direction = Direction::Forward();
0093 
0094   bool debug = false;
0095   std::string debugString;
0096   int debugMsgWidth = 60;
0097   int debugPfxWidth = 30;
0098 
0099   /// Contains: target aborters
0100   ActorList<PathLimitReached> abortList;
0101 
0102   const Acts::Logger& logger = Acts::getDummyLogger();
0103 };
0104 
0105 /// @brief mockup of propagtor state
0106 struct PropagatorState {
0107   /// Contains: stepping state
0108   SteppingState stepping;
0109   /// Contains: navigation state
0110   NavigationState navigation;
0111   /// Contains: options
0112   Options options;
0113 };
0114 
0115 // This test case checks that no segmentation fault appears
0116 // - this tests the collection of surfaces
0117 BOOST_DATA_TEST_CASE(
0118     loop_aborter_test,
0119     bdata::random((bdata::engine = std::mt19937(), bdata::seed = 21,
0120                    bdata::distribution = std::uniform_real_distribution<double>(
0121                        -std::numbers::pi, std::numbers::pi))) ^
0122         bdata::random(
0123             (bdata::engine = std::mt19937(), bdata::seed = 22,
0124              bdata::distribution = std::uniform_real_distribution<double>(
0125                  -std::numbers::pi, std::numbers::pi))) ^
0126         bdata::xrange(1),
0127     phi, deltaPhi, index) {
0128   (void)index;
0129   (void)deltaPhi;
0130 
0131   PropagatorState pState;
0132   pState.stepping.dir = Vector3(cos(phi), sin(phi), 0.);
0133   pState.stepping.p = 100_MeV;
0134 
0135   Stepper pStepper;
0136 
0137   auto& pathLimit = pState.options.abortList.get<PathLimitReached>();
0138   auto initialLimit = pathLimit.internalLimit;
0139 
0140   detail::setupLoopProtection(
0141       pState, pStepper, pathLimit, false,
0142       *Acts::getDefaultLogger("LoopProt", Logging::INFO));
0143 
0144   auto updatedLimit =
0145       pState.options.abortList.get<PathLimitReached>().internalLimit;
0146   BOOST_CHECK_LT(updatedLimit, initialLimit);
0147 }
0148 
0149 using BField = ConstantBField;
0150 using EigenStepper = Acts::EigenStepper<>;
0151 using EigenPropagator = Propagator<EigenStepper>;
0152 
0153 const int ntests = 100;
0154 const int skip = 0;
0155 
0156 // This test case checks that the propagator with loop LoopProtection
0157 // stops where expected
0158 BOOST_DATA_TEST_CASE(
0159     propagator_loop_protection_test,
0160     bdata::random((bdata::engine = std::mt19937(), bdata::seed = 20,
0161                    bdata::distribution = std::uniform_real_distribution<double>(
0162                        0.5_GeV, 10_GeV))) ^
0163         bdata::random(
0164             (bdata::engine = std::mt19937(), bdata::seed = 21,
0165              bdata::distribution = std::uniform_real_distribution<double>(
0166                  -std::numbers::pi, std::numbers::pi))) ^
0167         bdata::random(
0168             (bdata::engine = std::mt19937(), bdata::seed = 22,
0169              bdata::distribution = std::uniform_real_distribution<double>(
0170                  1., std::numbers::pi - 1.))) ^
0171         bdata::random((bdata::engine = std::mt19937(), bdata::seed = 23,
0172                        bdata::distribution =
0173                            std::uniform_int_distribution<std::uint8_t>(0, 1))) ^
0174         bdata::xrange(ntests),
0175     pT, phi, theta, charge, index) {
0176   if (index < skip) {
0177     return;
0178   }
0179 
0180   double px = pT * cos(phi);
0181   double py = pT * sin(phi);
0182   double pz = pT / tan(theta);
0183   double p = pT / sin(theta);
0184   double q = -1 + 2 * charge;
0185 
0186   const double Bz = 2_T;
0187   auto bField = std::make_shared<BField>(Vector3{0, 0, Bz});
0188   EigenStepper estepper(bField);
0189   EigenPropagator epropagator(std::move(estepper));
0190 
0191   // define start parameters
0192   BoundTrackParameters start = BoundTrackParameters::createCurvilinear(
0193       Vector4(0, 0, 0, 42), phi, theta, q / p, std::nullopt,
0194       ParticleHypothesis::pion());
0195 
0196   using PropagatorOptions = EigenPropagator::Options<ActorList<>>;
0197   PropagatorOptions options(tgContext, mfContext);
0198   options.maxSteps = 1e6;
0199   const auto& result = epropagator.propagate(start, options).value();
0200 
0201   // this test assumes state.options.loopFraction = 0.5
0202   CHECK_CLOSE_REL(px, -result.endParameters->momentum().x(), 1e-2);
0203   CHECK_CLOSE_REL(py, -result.endParameters->momentum().y(), 1e-2);
0204   CHECK_CLOSE_REL(pz, result.endParameters->momentum().z(), 1e-2);
0205 }
0206 
0207 }  // namespace Acts::Test