File indexing completed on 2025-08-06 08:11:39
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/Common.hpp"
0014 #include "Acts/Definitions/TrackParametrization.hpp"
0015 #include "Acts/Definitions/Units.hpp"
0016 #include "Acts/EventData/TransformationHelpers.hpp"
0017 #include "Acts/EventData/detail/GenerateParameters.hpp"
0018 #include "Acts/Geometry/GeometryContext.hpp"
0019 #include "Acts/Geometry/GeometryIdentifier.hpp"
0020 #include "Acts/Surfaces/PlaneSurface.hpp"
0021 #include "Acts/Surfaces/Surface.hpp"
0022 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0023 #include "Acts/Utilities/Result.hpp"
0024 #include "ActsFatras/Digitization/DigitizationError.hpp"
0025 #include "ActsFatras/Digitization/UncorrelatedHitSmearer.hpp"
0026 #include "ActsFatras/EventData/Barcode.hpp"
0027 #include "ActsFatras/EventData/Hit.hpp"
0028
0029 #include <algorithm>
0030 #include <array>
0031 #include <cstddef>
0032 #include <cstdint>
0033 #include <iterator>
0034 #include <limits>
0035 #include <memory>
0036 #include <ostream>
0037 #include <random>
0038 #include <utility>
0039
0040 namespace {
0041
0042 namespace bd = boost::unit_test::data;
0043
0044 using RandomGenerator = std::default_random_engine;
0045
0046 struct SterileSmearer {
0047 Acts::Result<std::pair<double, double>> operator()(double value,
0048 RandomGenerator& ) {
0049 return Acts::Result<std::pair<double, double>>(
0050 std::make_pair<double, double>(value + 0., 0.));
0051 }
0052 };
0053
0054 struct AddSmearer {
0055 double offset = 1.0;
0056
0057 Acts::Result<std::pair<double, double>> operator()(double value,
0058 RandomGenerator& ) {
0059 return Acts::Result<std::pair<double, double>>(
0060 std::make_pair<double, double>(value + offset, 3.));
0061 }
0062 };
0063
0064 struct InvalidSmearer {
0065 Acts::Result<std::pair<double, double>> operator()(double ,
0066 RandomGenerator& ) {
0067 return Acts::Result<std::pair<double, double>>(
0068 ActsFatras::DigitizationError::SmearingError);
0069 }
0070 };
0071
0072 struct Fixture {
0073 RandomGenerator rng;
0074
0075 Acts::GeometryIdentifier gid;
0076 ActsFatras::Barcode pid;
0077
0078 std::shared_ptr<Acts::Surface> surface;
0079 Acts::GeometryContext geoCtx;
0080
0081 Acts::BoundVector boundParams;
0082 Acts::FreeVector freeParams;
0083
0084 ActsFatras::Hit hit;
0085
0086 Fixture(uint64_t rngSeed)
0087 : rng(rngSeed),
0088 gid(Acts::GeometryIdentifier().setVolume(1).setLayer(2).setSensitive(
0089 3)),
0090 pid(ActsFatras::Barcode().setVertexPrimary(12).setParticle(23)),
0091 surface(Acts::Surface::makeShared<Acts::PlaneSurface>(
0092 Acts::Transform3(Acts::Translation3(3, 2, 1)))) {
0093 using namespace Acts::UnitLiterals;
0094 using Acts::VectorHelpers::makeVector4;
0095
0096 surface->assignGeometryId(gid);
0097
0098
0099 auto [par, cov] =
0100 Acts::detail::Test::generateBoundParametersCovariance(rng);
0101 boundParams = par;
0102 freeParams =
0103 Acts::transformBoundToFreeParameters(*surface, geoCtx, boundParams);
0104
0105
0106 Acts::Vector4 r4;
0107 r4.segment<3>(Acts::ePos0) = freeParams.segment<3>(Acts::eFreePos0);
0108 r4[Acts::eTime] = freeParams[Acts::eFreeTime];
0109
0110 Acts::Vector4 p4;
0111 p4.segment<3>(Acts::eMom0) =
0112 freeParams.segment<3>(Acts::eFreeDir0).normalized();
0113 p4[Acts::eEnergy] = 1;
0114 p4 *= std::abs(1_e / freeParams[Acts::eFreeQOverP]);
0115
0116 hit = ActsFatras::Hit(gid, pid, r4, p4, p4, 13);
0117 }
0118 };
0119
0120
0121
0122 const Acts::BoundIndices boundIndices[] = {
0123 Acts::eBoundLoc0, Acts::eBoundLoc1, Acts::eBoundTime,
0124 Acts::eBoundPhi, Acts::eBoundTheta,
0125 };
0126 const Acts::FreeIndices freeIndices[] = {
0127 Acts::eFreePos0, Acts::eFreePos1, Acts::eFreePos2, Acts::eFreeTime,
0128 Acts::eFreeDir0, Acts::eFreeDir1, Acts::eFreeDir2,
0129 };
0130
0131 constexpr auto tol = 128 * std::numeric_limits<double>::epsilon();
0132
0133 }
0134
0135 BOOST_AUTO_TEST_SUITE(FatrasUncorrelatedHitSmearer)
0136
0137 BOOST_DATA_TEST_CASE(Bound1, bd::make(boundIndices), index) {
0138 Fixture f(123);
0139 ActsFatras::BoundParametersSmearer<RandomGenerator, 1u> s;
0140 s.indices = {index};
0141
0142
0143 {
0144 s.smearFunctions.fill(SterileSmearer{});
0145 auto ret = s(f.rng, f.hit, *f.surface, f.geoCtx);
0146 BOOST_CHECK(ret.ok());
0147 auto [par, cov] = ret.value();
0148 CHECK_CLOSE_REL(par[0], f.boundParams[index], tol);
0149 }
0150
0151 {
0152 s.smearFunctions.fill(AddSmearer{-42.0});
0153 auto ret = s(f.rng, f.hit, *f.surface, f.geoCtx);
0154 BOOST_CHECK(ret.ok());
0155 auto [par, cov] = ret.value();
0156 CHECK_CLOSE_REL(par[0], f.boundParams[index] - 42.0, tol);
0157 }
0158
0159 {
0160 s.smearFunctions.fill(InvalidSmearer{});
0161 auto ret = s(f.rng, f.hit, *f.surface, f.geoCtx);
0162 BOOST_CHECK(!ret.ok());
0163 BOOST_CHECK(ret.error());
0164 }
0165 }
0166
0167 BOOST_AUTO_TEST_CASE(BoundAll) {
0168 Fixture f(12356);
0169
0170 ActsFatras::BoundParametersSmearer<RandomGenerator, std::size(boundIndices)>
0171 s;
0172 std::copy(std::begin(boundIndices), std::end(boundIndices),
0173 s.indices.begin());
0174
0175
0176 {
0177 s.smearFunctions.fill(SterileSmearer{});
0178 auto ret = s(f.rng, f.hit, *f.surface, f.geoCtx);
0179 BOOST_CHECK(ret.ok());
0180 auto [par, cov] = ret.value();
0181 for (std::size_t i = 0; i < s.indices.size(); ++i) {
0182 BOOST_TEST_INFO("Comparing smeared measurement "
0183 << i << " originating from bound parameter "
0184 << s.indices[i]);
0185 CHECK_CLOSE_REL(par[i], f.boundParams[s.indices[i]], tol);
0186 }
0187 }
0188
0189 {
0190 s.smearFunctions.fill(AddSmearer{-23.0});
0191 auto ret = s(f.rng, f.hit, *f.surface, f.geoCtx);
0192 BOOST_CHECK(ret.ok());
0193 auto [par, cov] = ret.value();
0194 for (std::size_t i = 0; i < s.indices.size(); ++i) {
0195 BOOST_TEST_INFO("Comparing smeared measurement "
0196 << i << " originating from bound parameter "
0197 << s.indices[i]);
0198 CHECK_CLOSE_REL(par[i], f.boundParams[s.indices[i]] - 23.0, tol);
0199 }
0200 }
0201
0202 {
0203 s.smearFunctions.fill(SterileSmearer{});
0204 s.smearFunctions[3] = InvalidSmearer{};
0205 auto ret = s(f.rng, f.hit, *f.surface, f.geoCtx);
0206 BOOST_CHECK(!ret.ok());
0207 BOOST_CHECK(ret.error());
0208 }
0209 }
0210
0211 BOOST_DATA_TEST_CASE(Free1, bd::make(freeIndices), index) {
0212 Fixture f(1234);
0213 ActsFatras::FreeParametersSmearer<RandomGenerator, 1u> s;
0214 s.indices = {index};
0215
0216
0217 {
0218 s.smearFunctions.fill(SterileSmearer{});
0219 auto ret = s(f.rng, f.hit);
0220 BOOST_CHECK(ret.ok());
0221 auto [par, cov] = ret.value();
0222 CHECK_CLOSE_REL(par[0], f.freeParams[index], tol);
0223 }
0224
0225 {
0226 s.smearFunctions.fill(AddSmearer{-42.0});
0227 auto ret = s(f.rng, f.hit);
0228 BOOST_CHECK(ret.ok());
0229 auto [par, cov] = ret.value();
0230 CHECK_CLOSE_REL(par[0], f.freeParams[index] - 42.0, tol);
0231 }
0232
0233 {
0234 s.smearFunctions.fill(InvalidSmearer{});
0235 auto ret = s(f.rng, f.hit);
0236 BOOST_CHECK(!ret.ok());
0237 BOOST_CHECK(ret.error());
0238 }
0239 }
0240
0241 BOOST_AUTO_TEST_CASE(FreeAll) {
0242 Fixture f(123567);
0243
0244 ActsFatras::FreeParametersSmearer<RandomGenerator, std::size(freeIndices)> s;
0245 std::copy(std::begin(freeIndices), std::end(freeIndices), s.indices.begin());
0246
0247
0248 {
0249 s.smearFunctions.fill(SterileSmearer{});
0250 auto ret = s(f.rng, f.hit);
0251 BOOST_CHECK(ret.ok());
0252 auto [par, cov] = ret.value();
0253 for (std::size_t i = 0; i < s.indices.size(); ++i) {
0254 BOOST_TEST_INFO("Comparing smeared measurement "
0255 << i << " originating from free parameter "
0256 << s.indices[i]);
0257 CHECK_CLOSE_REL(par[i], f.freeParams[s.indices[i]], tol);
0258 }
0259 }
0260
0261 {
0262 s.smearFunctions.fill(AddSmearer{42.0});
0263 auto ret = s(f.rng, f.hit);
0264 BOOST_CHECK(ret.ok());
0265 auto [par, cov] = ret.value();
0266 for (std::size_t i = 0; i < s.indices.size(); ++i) {
0267 BOOST_TEST_INFO("Comparing smeared measurement "
0268 << i << " originating from free parameter "
0269 << s.indices[i]);
0270 CHECK_CLOSE_REL(par[i], f.freeParams[s.indices[i]] + 42.0, tol);
0271 }
0272 }
0273
0274 {
0275 s.smearFunctions.fill(SterileSmearer{});
0276 s.smearFunctions[3] = InvalidSmearer{};
0277 auto ret = s(f.rng, f.hit);
0278 BOOST_CHECK(!ret.ok());
0279 BOOST_CHECK(ret.error());
0280 }
0281 }
0282
0283 BOOST_AUTO_TEST_SUITE_END()