15#define BOOST_TEST_MODULE ITSMFT MFTNormalizedRefit
16#define BOOST_TEST_MAIN
17#define BOOST_TEST_DYN_LINK
27#include <boost/test/unit_test.hpp>
34#include "MFTTracking/Constants.h"
43constexpr float Bz = 0.f;
44constexpr float DefaultSigma2 = 2.5e-7f;
52 const float transverseLength = std::hypot(dx, dy);
53 const float qOverPt = trackletMinPt > 0.f ? 1.f / trackletMinPt : 0.f;
67 const float qOverPtSigma = std::clamp(std::abs(qOverPt), 1.f, 10.f);
68 state.
covariance[packedCovarianceIndex(4, 4)] = qOverPtSigma * qOverPtSigma;
76struct StraightTrackGeometry {
77 std::array<float, NLayers>
x{};
78 std::array<float, NLayers>
y{};
79 std::array<float, NLayers>
z{};
82 explicit StraightTrackGeometry(
float slope) : xSlope(
slope)
85 const float z0 = zLayer[0];
96 std::array<std::vector<SurfaceMeasurement>, NLayers> storage;
97 std::array<std::vector<GlobalMeasurement>, NLayers> globalStorage;
98 std::vector<gsl::span<const GlobalMeasurement>> layerGlobals = std::vector<gsl::span<const GlobalMeasurement>>(NLayers);
99 std::vector<SurfaceDescriptor> catalogSurfaces;
106 explicit RefitFixture(
const StraightTrackGeometry& geometry,
int hits = NLayers)
109 params.MinTrackLength = 5;
110 params.MinPt.assign(NLayers + 1, 0.f);
113 catalogSurfaces.resize(NLayers);
115 catalogSurfaces[
layer].detectorSurfaceIndex =
static_cast<uint16_t
>(
layer);
116 catalogSurfaces[
layer].kind = SurfaceKind::Disk;
119 catalog =
SurfaceCatalogView{catalogSurfaces.data(),
static_cast<uint32_t
>(catalogSurfaces.size())};
121 std::make_shared<BoundedMemoryResource>()));
126 DefaultSigma2, DefaultSigma2);
127 seed.getClusters()[
layer] = 0;
128 mask |=
static_cast<uint16_t
>(uint16_t(1) <<
layer);
133 const int innerLayer = 0;
134 const int outerLayer = hits - 1;
135 seed.state() = makeDiskRefitStateFixture(
136 storage[innerLayer][0], storage[outerLayer][0],
params.TrackletMinPt);
139 void setMeasurement(
int layer,
float x,
float y,
float z,
float uu,
float vv,
float uv = 0.f)
144 m.covariance.uu = uu;
145 m.covariance.vv = vv;
146 m.covariance.uv = uv;
149 global.radius = std::hypot(
x,
y);
150 global.covariance = {uu, uv, 0.f, vv, 0.f, 0.f};
151 global.clusterId = 0u;
152 storage[
layer].assign(1,
m);
153 globalStorage[
layer].assign(1, global);
161 for (std::size_t cluster = 0; cluster < globalStorage[
layer].size(); ++cluster) {
163 storage[
layer][cluster]);
176 if (!
fitTrackSeedLegs(fixture.seed, fixture.frame, fixture.layerGlobals, fixture.catalog, Bz,
177 fixture.params.ShiftRefToCluster, fixture.params.MaxChi2ClusterAttachment,
178 fixture.params.MaxChi2NDF, fixture.params.RepeatRefitOut,
179 gsl::span<const float>(fixture.params.MinPt),
180 innerState, outerState,
chi2)) {
183 candidate.
seed = fixture.seed;
196 for (
int i = 0;
i < 5; ++
i) {
200 for (
int i = 0;
i < 15; ++
i) {
217 const StraightTrackGeometry geometry(0.3f);
221 BOOST_REQUIRE(refit(
reference, referenceTrack));
228 RefitFixture perturbed(geometry);
229 auto perturbedMeasurement = perturbed.storage[5].front();
230 perturbedMeasurement.frame.u += 0.05f;
231 perturbed.storage[5].assign(1, perturbedMeasurement);
234 const bool perturbedOk = refit(perturbed, perturbedTrack);
240 const StraightTrackGeometry geometry(0.3f);
244 BOOST_REQUIRE(refit(
reference, referenceTrack));
252 RefitFixture loose(geometry);
254 auto m = loose.storage[
layer].front();
255 m.covariance.uu *= 400.f;
256 m.covariance.vv *= 400.f;
257 loose.storage[
layer].assign(1,
m);
260 BOOST_REQUIRE(refit(loose, looseTrack));
272 const StraightTrackGeometry geometry(0.3f);
273 RefitFixture fx(geometry);
274 auto m = fx.storage[3].front();
275 m.frame.u = std::numeric_limits<float>::quiet_NaN();
276 fx.storage[3].assign(1,
m);
281 checkTrackUnchanged(before, track);
286 const StraightTrackGeometry geometry(0.3f);
287 RefitFixture fx(geometry);
288 auto m = fx.storage[3].front();
289 m.frame.q = std::numeric_limits<float>::infinity();
290 fx.storage[3].assign(1,
m);
295 checkTrackUnchanged(before, track);
300 const StraightTrackGeometry geometry(0.3f);
301 RefitFixture fx(geometry);
302 auto m = fx.storage[3].front();
303 m.covariance.uu = std::numeric_limits<float>::quiet_NaN();
304 fx.storage[3].assign(1,
m);
309 checkTrackUnchanged(before, track);
314 const StraightTrackGeometry geometry(0.3f);
315 RefitFixture fx(geometry);
316 auto m = fx.storage[3].front();
317 m.covariance.vv = -1.f;
318 fx.storage[3].assign(1,
m);
323 checkTrackUnchanged(before, track);
328 const StraightTrackGeometry geometry(0.3f);
329 RefitFixture fx(geometry);
330 fx.seed.getClusters()[3] = 99;
335 checkTrackUnchanged(before, track);
340 const StraightTrackGeometry geometry(0.3f);
341 RefitFixture fx(geometry);
342 auto m = fx.globalStorage[3].front();
343 m.clusterId = std::numeric_limits<uint32_t>::max();
344 fx.globalStorage[3].assign(1,
m);
345 fx.layerGlobals[3] = fx.globalStorage[3];
350 checkTrackUnchanged(before, track);
355 RefitFixture fixture(StraightTrackGeometry{0.3f});
358 std::vector<gsl::span<const GlobalMeasurement>> layers(
count);
366 fixture.params.ShiftRefToCluster, fixture.params.MaxChi2ClusterAttachment,
367 fixture.params.MaxChi2NDF,
true, fixture.params.MinPt,
368 after.track.innerState, after.track.outerState, after.track.chi2));
370 checkTrackUnchanged(before, after);
376 RefitFixture fixture(StraightTrackGeometry{0.3f});
377 for (
const bool repeat : {
false,
true}) {
378 fixture.params.RepeatRefitOut = repeat;
379 fixture.layerGlobals.resize(NLayers);
381 BOOST_REQUIRE(refit(fixture, compact));
386 BOOST_REQUIRE(refit(fixture, maximum));
387 checkTrackUnchanged(compact, maximum);
395 const StraightTrackGeometry geometry(0.3f);
397 RefitFixture fx(geometry);
403 fx.seed.setHitLayerMask(
mask);
406 BOOST_REQUIRE(refit(fx, track));
423 const StraightTrackGeometry geometry(0.3f);
427 BOOST_REQUIRE(refit(
reference, referenceTrack));
429 RefitFixture withUv(geometry);
435 withUv.params.MaxChi2ClusterAttachment = 1.e4f;
436 withUv.params.MaxChi2NDF = 1.e4f;
438 auto m = withUv.storage[
layer].front();
441 m.covariance.uv = 0.05f * std::sqrt(
m.covariance.uu *
m.covariance.vv);
442 withUv.storage[
layer].assign(1,
m);
445 BOOST_REQUIRE(refit(withUv, withUvTrack));
458 const StraightTrackGeometry geometry(0.3f);
459 std::array<std::vector<SurfaceMeasurement>, NLayers> storage;
460 std::array<std::vector<GlobalMeasurement>, NLayers> globalStorage;
461 std::vector<gsl::span<const GlobalMeasurement>> layerGlobals = std::vector<gsl::span<const GlobalMeasurement>>(NLayers);
462 std::vector<SurfaceDescriptor> catalogSurfaces(NLayers);
464 catalogSurfaces[
layer].kind = SurfaceKind::Disk;
467 SurfaceCatalogView catalog{catalogSurfaces.data(),
static_cast<uint32_t
>(catalogSurfaces.size())};
471 params.MinPt.assign(NLayers + 1, 0.f);
478 m.covariance.uu = DefaultSigma2;
479 m.covariance.vv = DefaultSigma2;
481 distractor.covariance.uu = std::numeric_limits<float>::quiet_NaN();
484 global.radius = std::hypot(geometry.x[
layer], geometry.y[
layer]);
485 global.covariance = {DefaultSigma2, 0.f, 0.f, DefaultSigma2, 0.f, 0.f};
486 global.clusterId = 1u;
487 auto distractorGlobal = global;
488 distractorGlobal.position.x += 100.f;
489 distractorGlobal.radius = std::hypot(distractorGlobal.position.x, distractorGlobal.position.y);
490 distractorGlobal.clusterId = 0u;
491 storage[
layer] = {distractor,
m};
492 globalStorage[
layer] = {global, distractorGlobal};
495 seed.getClusters()[
layer] = 0;
496 mask |=
static_cast<uint16_t
>(uint16_t(1) <<
layer);
500 seed.state() = makeDiskRefitStateFixture(
501 storage[0][1], storage[NLayers - 1][1],
params.TrackletMinPt);
504 std::vector<std::vector<GlobalMeasurement>> globals(NLayers);
505 std::vector<std::vector<SurfaceMeasurement>> measurements(NLayers);
512 std::make_shared<BoundedMemoryResource>()));
514 for (std::size_t cluster = 0; cluster < globals[
layer].size(); ++cluster) {
516 measurements[
layer][cluster]);
525 params.RepeatRefitOut, gsl::span<const float>(
params.MinPt),
526 innerState, outerState,
chi2));
528 track.track.innerState = innerState;
529 track.track.outerState = outerState;
530 track.track.chi2 =
chi2;
543 for (
double bz : {-5., 5.}) {
544 for (
double qOverPt : {-5., -1., -.05, .05, 1., 5.}) {
545 for (
double phi : {-.7, 0., 1.8}) {
546 for (
double scale : {0.01, 1.}) {
547 std::vector<detail::CircleFitPoint> points;
548 const double curvature = qOverPt * bz * o2::constants::math::B2C;
549 for (
double arc : {2., 3., 4., 20., 25., 34., 40.}) {
551 const double x = std::sin(curvature * arc) / curvature;
552 const double y = 2 * std::pow(std::sin(curvature * arc / 2), 2) / curvature;
553 points.push_back({
static_cast<float>(2 +
x * std::cos(phi) -
y * std::sin(phi)),
554 static_cast<float>(-1 +
x * std::sin(phi) +
y * std::cos(phi)), 1.e-6f, 2.e-7f, 2.e-6f});
557 BOOST_REQUIRE(std::isfinite(fitted));
561 double coordinateScale = 0.;
562 for (
const auto& point : points) {
563 coordinateScale = std::max(coordinateScale, std::max(std::abs(
double(point.x)), std::abs(
double(point.y))));
565 const double dx = double(points.back().x) - points.front().x;
566 const double dy = double(points.back().y) - points.front().y;
567 const double quantizationTolerance = 8 * std::numeric_limits<float>::epsilon() * coordinateScale /
568 ((dx * dx + dy * dy) * std::abs(bz * o2::constants::math::B2C));
569 BOOST_CHECK_SMALL(fitted - qOverPt, quantizationTolerance + 2.e-6 * std::max(1., std::abs(qOverPt)));
578 std::array<detail::CircleFitPoint, 3> points{{{0.f, 0.f, 1.e-6f, 0.f, 1.e-6f},
579 {1.f, .01f, 1.e-6f, 0.f, 1.e-6f},
580 {2.f, .04f, 1.e-6f, 0.f, 1.e-6f}}};
585 auto invalid = points;
586 invalid.back() = invalid.front();
589 invalid[1].xx = invalid[1].yy = 0.;
592 invalid[1].x = std::numeric_limits<float>::quiet_NaN();
600 const std::array<detail::CircleFitPoint, 6> points{{{0.f, .0003f, 1.e-6f, 2.e-7f, 4.e-6f},
601 {1.f, .0012f, 5.e-6f, -5.e-7f, 1.e-6f},
602 {2.f, -.001f, 2.e-6f, 6.e-7f, 3.e-6f},
603 {4.f, -.0037f, 1.e-6f, -3.e-7f, 2.e-6f},
604 {8.f, -.0191f, 6.e-6f, 8.e-7f, 1.e-6f},
605 {12.f, -.051f, 2.e-6f, 4.e-7f, 5.e-6f}}};
607 const std::array<double, 4> angles{-2.4, -.7, 0., 1.8};
608 const std::array<double, 4> references{0.57124524009151501, 0.57124303442230506,
609 0.5712510057031307, 0.57124927069565135};
610 for (std::size_t rotation = 0; rotation < angles.size(); ++rotation) {
611 const double angle = angles[rotation];
612 const double cs = std::cos(
angle), sn = std::sin(
angle);
613 auto rotated = points;
614 for (std::size_t
i = 0;
i < points.size(); ++
i) {
615 const auto& point = points[
i];
616 rotated[
i] = {
static_cast<float>(3. + cs * point.x - sn * point.y),
617 static_cast<float>(-2. + sn * point.x + cs * point.y),
618 static_cast<float>(cs * cs * point.xx - 2 * cs * sn * point.xy + sn * sn * point.yy),
619 static_cast<float>(cs * sn * point.xx + (cs * cs - sn * sn) * point.xy - cs * sn * point.yy),
620 static_cast<float>(sn * sn * point.xx + 2 * cs * sn * point.xy + cs * cs * point.yy)};
629 std::array<detail::CircleFitPoint, MaxLayoutSurfaces + 1> points;
630 const double curvature = 5. * o2::constants::math::B2C;
631 for (std::size_t
i = 0;
i < points.size(); ++
i) {
632 const double arc = 1. +
i;
633 points[
i] = {
static_cast<float>(std::sin(curvature * arc) / curvature),
634 static_cast<float>(2 * std::pow(std::sin(curvature * arc / 2), 2) / curvature),
635 1.e-6f, 0.f, 1.e-6f};
645 const std::array<double, 3> angles{-.7, 0., 1.8};
646 const std::array<std::array<double, 2>, 3> references{{{-0.049988686038833739, 0.050272146766691041},
647 {-0.049999995096480683, 0.049999995096480725},
648 {-0.050008335297723923, 0.050037910305885301}}};
649 for (std::size_t rotation = 0; rotation < angles.size(); ++rotation) {
650 for (
int sign = 0; sign < 2; ++sign) {
651 const double curvature = (sign ? .05 : -.05) * 5 * o2::constants::math::B2C;
652 const double phi = angles[rotation];
653 std::array<detail::CircleFitPoint, 7> points;
654 for (std::size_t
i = 0;
i < points.size(); ++
i) {
655 const double arc = (2. + 38. *
i / 6) * .01;
656 const double x = std::sin(curvature * arc) / curvature;
657 const double y = 2 * std::pow(std::sin(curvature * arc / 2), 2) / curvature;
658 points[
i] = {
static_cast<float>(
x * std::cos(phi) -
y * std::sin(phi)),
659 static_cast<float>(
x * std::sin(phi) +
y * std::cos(phi)), 1.e-6f, 2.e-7f, 2.e-6f};
Passive common TimeFrame owner.
GPU-portable whole-track seed for common CA tracking.
static constexpr int MaxSurfaces
GLenum const GLfloat * params
GLenum GLuint GLint GLint layer
GLdouble GLdouble GLdouble z
constexpr int UnusedIndex
float estimateCircleQOverPt(gsl::span< const CircleFitPoint > points, float bz) noexcept
constexpr float MinCircleFitBz
bool fitTrackSeedLegs(const TrackSeed &seed, const TimeFrame &frame, gsl::span< const gsl::span< const GlobalMeasurement > > layerGlobals, SurfaceCatalogView surfaceCatalog, float bz, bool shiftReferenceToMeasurement, float maxChi2ClusterAttachment, float maxChi2NDF, bool repeatRefitOut, gsl::span< const float > minPt, SurfaceTrackState &outParamIn, SurfaceTrackState &outParamOut, float &outChi2) noexcept
constexpr uint32_t MaxLayoutSurfaces
constexpr Int_t LayersNumber
constexpr std::array< Float_t, LayersNumber > LayerZCoordinate()
int MinTrackLength
General parameters.
SurfaceTrackState outerState
SurfaceTrackState innerState
SurfaceCovariance2F covariance
float referenceCoordinate
void resetTimeFrame() noexcept
void addMeasurement(LayerId surface, GlobalMeasurement global, const SurfaceMeasurement &measurement)
bool configure(DetectorConfiguration &&layout, std::size_t maxEdges, std::size_t maxCells, std::shared_ptr< BoundedMemoryResource > memoryPool)
BOOST_AUTO_TEST_CASE(NormalizedGlobalCoordinateChangeAltersOutput)
BOOST_CHECK_EQUAL(triggersD.size(), triggers.size())