File indexing completed on 2026-05-27 07:24:23
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include "detray/propagator/actors/pointwise_material_interactor.hpp"
0011 #include "detray/tracks/tracks.hpp"
0012
0013
0014 #include "detray/test/framework/types.hpp"
0015 #include "detray/test/utils/random_scatterer.hpp"
0016 #include "detray/test/utils/scattering_helper.hpp"
0017 #include "detray/test/utils/statistics.hpp"
0018
0019
0020 #include <gtest/gtest.h>
0021
0022
0023 #include <algorithm>
0024 #include <random>
0025 #include <vector>
0026
0027 using namespace detray;
0028
0029 using test_algebra = test::algebra;
0030 using scalar = test::scalar;
0031 using vector3 = test::vector3;
0032
0033 namespace {
0034 std::random_device rd{};
0035 std::mt19937_64 generator{rd()};
0036 }
0037
0038
0039 GTEST_TEST(detray_simulation, scattering_helper) {
0040 generator.seed(0u);
0041
0042 const vector3 dir{2.f, 2.f, 4.f};
0043 const scalar scattering_angle{0.1f};
0044
0045
0046 const vector3 u = unit_vectors<vector3>().make_curvilinear_unit_u(dir);
0047
0048
0049 const vector3 w = vector::cross(dir, u);
0050
0051 std::vector<scalar> angle_diffs;
0052
0053 std::size_t n_samples{100000u};
0054 for (std::size_t i = 0u; i < n_samples; i++) {
0055
0056 const vector3 new_dir =
0057 scattering_helper<test_algebra>()(dir, scattering_angle, generator);
0058
0059
0060
0061 const scalar sign = vector::dot(w, new_dir) > 0 ? 1.f : -1.f;
0062
0063
0064 scalar cos_theta =
0065 vector::dot(dir, new_dir) / (vector::norm(dir) * vector::norm(new_dir));
0066
0067
0068 cos_theta = std::clamp(cos_theta, scalar{-1.f}, scalar{1.f});
0069
0070
0071 const scalar angle = sign * std::acos(cos_theta);
0072
0073 angle_diffs.push_back(angle);
0074 }
0075
0076 EXPECT_NEAR(statistics::mean(angle_diffs), 0.f, 1e-3f);
0077
0078
0079 const scalar stddev = std::sqrt(statistics::rms(angle_diffs, 0.f));
0080 EXPECT_NEAR((stddev - scattering_angle) / scattering_angle, 0.f, 1e-2f);
0081 }
0082
0083
0084 GTEST_TEST(detray_simulation, angle_update) {
0085 generator.seed(0u);
0086
0087
0088 vector3 dir{1.f, 2.f, 3.f};
0089 dir = vector::normalize(dir);
0090
0091 const scalar phi0 = vector::phi(dir);
0092 const scalar theta0 = vector::theta(dir);
0093
0094
0095 const scalar projected_scattering_angle{0.01f};
0096
0097
0098 auto bound_cov = matrix::zero<
0099 typename bound_track_parameters<test_algebra>::covariance_type>();
0100
0101
0102
0103
0104
0105 actor::pointwise_material_interactor<test_algebra>().update_angle_variance(
0106 bound_cov, dir, projected_scattering_angle);
0107
0108
0109 std::vector<scalar> phis;
0110 std::vector<scalar> thetas;
0111 std::size_t n_samples{100000u};
0112 for (std::size_t i = 0u; i < n_samples; i++) {
0113 const auto new_dir = actor::random_scatterer<test_algebra>().scatter(
0114 dir, projected_scattering_angle, generator);
0115 phis.push_back(vector::phi(new_dir));
0116 thetas.push_back(vector::theta(new_dir));
0117 }
0118
0119
0120 const auto var_phi = getter::element(bound_cov, e_bound_phi, e_bound_phi);
0121 const auto var_theta =
0122 getter::element(bound_cov, e_bound_theta, e_bound_theta);
0123 EXPECT_NEAR((var_phi - statistics::rms(phis, phi0)) / var_phi, 0.f, 1e-2f);
0124 EXPECT_NEAR((var_theta - statistics::rms(thetas, theta0)) / var_theta, 0.f,
0125 1e-2f);
0126 }