12#define BOOST_TEST_MODULE ITSMFTTrackingTripletFitting
13#include <boost/test/unit_test.hpp>
28constexpr double Radius = 50.;
29constexpr double TanLambda = 0.4;
34 return {4.e-6f, 0.8e-6f, -0.4e-6f, 3.e-6f, 0.3e-6f, 5.e-6f};
42 measurement.covariance = covariance;
46std::array<GlobalMeasurement, 3> makeHelixMeasurements()
48 const std::array<double, 3> angles{0.1, 0.16, 0.25};
49 std::array<GlobalMeasurement, 3> measurements{};
50 for (std::size_t
i = 0;
i < measurements.size(); ++
i) {
51 measurements[
i].position = {
static_cast<float>(3. + Radius * std::cos(angles[
i])),
52 static_cast<float>(-2. + Radius * std::sin(angles[
i])),
53 static_cast<float>(1.5 + Radius * angles[
i] * TanLambda)};
54 measurements[
i].covariance = makeCovariance();
59std::array<GlobalMeasurement, 4> makeAdjacentHelixMeasurements()
61 const std::array<double, 4> angles{0.1, 0.16, 0.25, 0.33};
62 std::array<GlobalMeasurement, 4> measurements{};
63 for (std::size_t
i = 0;
i < measurements.size(); ++
i) {
64 measurements[
i].position = {
static_cast<float>(3. + Radius * std::cos(angles[
i])),
65 static_cast<float>(-2. + Radius * std::sin(angles[
i])),
66 static_cast<float>(1.5 + Radius * angles[
i] * TanLambda)};
67 measurements[
i].covariance = makeCovariance();
72std::array<TripletFitFactor, 2> fitAdjacentFactors(
73 const std::array<GlobalMeasurement, 4>& measurements)
75 const std::array<GlobalMeasurement, 3>
first{
76 measurements[0], measurements[1], measurements[2]};
77 const std::array<GlobalMeasurement, 3> second{
78 measurements[1], measurements[2], measurements[3]};
79 std::array<TripletFitFactor, 2> factors{};
88 const double cosine = std::cos(
angle);
89 const double sine = std::sin(
angle);
90 return {
static_cast<float>(cosine * cosine * covariance.
xx - 2. * sine * cosine * covariance.
xy + sine * sine * covariance.
yy),
91 static_cast<float>(sine * cosine * covariance.
xx + (cosine * cosine - sine * sine) * covariance.
xy -
92 sine * cosine * covariance.
yy),
93 static_cast<float>(cosine * covariance.
xz - sine * covariance.
yz),
94 static_cast<float>(sine * sine * covariance.
xx + 2. * sine * cosine * covariance.
xy + cosine * cosine * covariance.
yy),
95 static_cast<float>(sine * covariance.
xz + cosine * covariance.
yz),
99void checkClose(
double actual,
double expected,
double relativeTolerance,
double absoluteTolerance = 0.)
101 BOOST_CHECK_SMALL(actual -
expected,
102 std::max(absoluteTolerance, relativeTolerance * std::max(std::abs(actual), std::abs(
expected))));
106 const std::array<GlobalMeasurement, 3>& measurements,
107 bool leftTheta,
bool rightTheta)
109 double covariance = 0.;
110 for (std::size_t hit = 0; hit < measurements.size(); ++hit) {
111 const auto&
left = leftTheta ? factor.
h[hit].theta : factor.
h[hit].phi;
112 const auto&
right = rightTheta ? factor.
h[hit].theta : factor.
h[hit].phi;
113 const auto&
v = measurements[hit].covariance;
125 const auto measurements = makeHelixMeasurements();
128 BOOST_REQUIRE(factor.isValid());
129 const double referenceCurvature = -
static_cast<double>(factor.psi.phi) / factor.rho.phi;
130 const double expectedCurvature = (1. / Radius) / std::sqrt(1. + TanLambda * TanLambda);
131 checkClose(referenceCurvature, expectedCurvature, 4.e-4);
134 BOOST_CHECK_SMALL(
static_cast<double>(factor.psi.theta) +
135 static_cast<double>(factor.rho.theta) * referenceCurvature,
137 BOOST_CHECK_GT(factorCovariance(factor, measurements,
true,
true), 0.);
138 BOOST_CHECK_NE(factorCovariance(factor, measurements,
true,
false), 0.);
144 const std::array<GlobalMeasurement, 4> measurements{{
145 makeMeasurement(0.f, 0.f, 0.f, exact),
146 makeMeasurement(1.f, 0.f, 0.f, exact),
147 makeMeasurement(2.f, 0.f, 0.f, exact),
148 makeMeasurement(3.f, 0.f, 0.f, exact),
150 std::array<TripletFitFactor, 2> factors{};
151 factors[0].psi = {1.f, 2.f};
152 factors[0].rho = {1.f, 1.f};
153 factors[1].psi = {3.f, 4.f};
154 factors[1].rho = {1.f, 1.f};
158 const double rhoKpsi = 1. / 4. + 2. / 4. + 3. / 9. + 4. / 9.;
159 const double rhoKrho = 1. / 4. + 1. / 4. + 1. / 9. + 1. / 9.;
160 const double psiKpsi = 1. / 4. + 4. / 4. + 9. / 9. + 16. / 9.;
161 checkClose(
result.curvature, -rhoKpsi / rhoKrho, 2.e-6);
162 checkClose(
result.curvatureVariance, 1. / rhoKrho, 2.e-6);
163 checkClose(
result.chi2, psiKpsi - rhoKpsi * rhoKpsi / rhoKrho, 2.e-6);
169 std::array<GlobalMeasurement, 4> measurements{{
170 makeMeasurement(0.f, 0.f, 0.f, exact),
171 makeMeasurement(1.f, 0.f, 0.f, {2.f, 0.5f, 0.f, 3.f, 0.f, 0.f}),
172 makeMeasurement(2.f, 0.f, 0.f, exact),
173 makeMeasurement(3.f, 0.f, 0.f, exact),
175 std::array<TripletFitFactor, 2> factors{};
176 factors[0].rho.phi = 1.f;
177 factors[1].rho.phi = 1.f;
178 factors[0].h[1].theta = {1.f, 2.f, 0.f};
179 factors[0].h[1].phi = {-1.f, 1.f, 0.f};
180 factors[1].h[0].theta = {3.f, -2.f, 0.f};
181 factors[1].h[0].phi = {2.f, 4.f, 0.f};
185 {100.f, 100.f}, correlated));
190 auto independentFactors = factors;
191 auto independentMeasurements = measurements;
192 independentFactors[1].h[2] = independentFactors[1].h[0];
193 independentFactors[1].h[0] = {};
194 independentMeasurements[3].covariance = measurements[1].covariance;
197 independentMeasurements, {100.f, 100.f}, independent));
198 BOOST_CHECK_NE(correlated.curvatureVariance, independent.curvatureVariance);
204 const std::array<GlobalMeasurement, 4> measurements{{
205 makeMeasurement(0.f, 0.f, 0.f, exact),
206 makeMeasurement(1.f, 0.f, 1.f, exact),
207 makeMeasurement(2.f, 0.f, 2.f, exact),
208 makeMeasurement(3.f, 0.f, 3.f, exact),
210 std::array<TripletFitFactor, 2> factors{};
211 factors[0].rho = {1.f, 1.f};
212 factors[1].rho = {1.f, 1.f};
215 const double expectedPrecision = 1. / 4. + 1. / 8. + 1. / 9. + 1. / 18.;
216 checkClose(
result.curvatureVariance, 1. / expectedPrecision, 2.e-6);
221 const auto measurements = makeAdjacentHelixMeasurements();
222 const std::array<float, 2> angularVariance{1.e-8f, 2.e-8f};
223 const auto factors = fitAdjacentFactors(measurements);
226 const double expectedCurvature = (1. / Radius) / std::sqrt(1. + TanLambda * TanLambda);
227 checkClose(
result.curvature, expectedCurvature, 4.e-4);
230 BOOST_CHECK_SMALL(
result.chi2, 2.e-6f);
231 BOOST_CHECK_GT(
result.curvatureVariance, 0.);
236 const auto original = makeAdjacentHelixMeasurements();
237 auto rotated = original;
238 const double angle = 0.73;
239 const double cosine = std::cos(
angle);
240 const double sine = std::sin(
angle);
241 for (
auto& measurement : rotated) {
242 const double x = measurement.x;
243 const double y = measurement.y;
244 measurement.x =
static_cast<float>(cosine *
x - sine *
y);
245 measurement.y =
static_cast<float>(sine *
x + cosine *
y);
246 measurement.covariance = rotateCovarianceAroundZ(measurement.covariance,
angle);
248 const std::array<float, 2> angularVariance{2.e-8f, 3.e-8f};
249 const auto originalFactors = fitAdjacentFactors(original);
250 const auto rotatedFactors = fitAdjacentFactors(rotated);
257 checkClose(second.curvature,
first.curvature, 2.e-6);
258 checkClose(second.curvatureVariance,
first.curvatureVariance, 5.e-2);
259 checkClose(second.chi2,
first.chi2, 1.e-5, 5.e-7);
265 const std::array<GlobalMeasurement, 3> measurements{{
266 makeMeasurement(1.f, 2.f, 3.f, covariance),
267 makeMeasurement(2.f, 2.f, 3.5f, covariance),
268 makeMeasurement(4.f, 2.f, 4.5f, covariance),
272 BOOST_REQUIRE(factor.isValid());
273 BOOST_CHECK_SMALL(-
static_cast<double>(factor.psi.phi) / factor.rho.phi, 1.e-15);
279 sentinel.
psi = {1.f, 2.f};
280 sentinel.rho = {3.f, 4.f};
281 auto measurements = makeHelixMeasurements();
284 measurements[1].position = measurements[0].position;
291 const auto measurements = makeHelixMeasurements();
292 constexpr int Repetitions = 20000;
293 double checksum = 0.;
294 const auto start = std::chrono::steady_clock::now();
295 for (
int iteration = 0; iteration < Repetitions; ++iteration) {
298 checksum += factor.psi.theta + factor.psi.phi + factor.rho.theta + factor.rho.phi;
300 const auto elapsed = std::chrono::steady_clock::now() -
start;
301 const double nanosecondsPerFit =
302 std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count() /
303 static_cast<double>(Repetitions);
304 BOOST_TEST_MESSAGE(
"triplet-factor construction host cost: " << nanosecondsPerFit <<
" ns/factor; checksum=" << checksum);
305 BOOST_CHECK_NE(checksum, 0.);
310 const auto measurements = makeAdjacentHelixMeasurements();
311 const std::array<float, 2> angularVariance{2.e-7f, 3.e-7f};
312 const auto factors = fitAdjacentFactors(measurements);
313 constexpr int Repetitions = 20000;
314 double checksum = 0.;
315 const auto start = std::chrono::steady_clock::now();
316 for (
int iteration = 0; iteration < Repetitions; ++iteration) {
321 const auto elapsed = std::chrono::steady_clock::now() -
start;
322 const double nanosecondsPerFit =
323 std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count() /
324 static_cast<double>(Repetitions);
325 BOOST_TEST_MESSAGE(
"adjacent triplet-factor fit host cost: " << nanosecondsPerFit <<
" ns/fit; checksum=" << checksum);
326 BOOST_CHECK_GT(checksum, 0.);
GLdouble GLdouble GLdouble z
bool fitAdjacentTripletFactors(const TripletFitFactor &firstFactor, const TripletFitFactor &secondFactor, const std::array< GlobalMeasurement, 4 > &measurements, const std::array< float, 2 > &angularVariance, AdjacentTripletFitResult &result) noexcept
bool makeTripletFitFactor(const std::array< GlobalMeasurement, 3 > &measurements, TripletFitFactor &factor) noexcept
std::array< TripletHitJacobian, 3 > h
std::map< std::string, ID > expected
BOOST_AUTO_TEST_CASE(ExactHelixProducesAConsistentFactor)
BOOST_CHECK_EQUAL(triggersD.size(), triggers.size())