12#define BOOST_TEST_MODULE ITSMFTPropagator
13#define BOOST_TEST_MAIN
14#define BOOST_TEST_DYN_LINK
15#include <boost/test/unit_test.hpp>
29#if __has_include("ITSMFTTracking/detail/SurfaceStateOperations.h") || __has_include("ITSMFTTracking/BarrelSurfaceStateOperations.h") || __has_include("ITSMFTTracking/ForwardSurfaceStateOperations.h")
30#error "coordinate-family state operations must be declared in Propagator.h"
39bool bitEqual(
const T& lhs,
const T& rhs)
41 return std::memcmp(&lhs, &rhs,
sizeof(T)) == 0;
60 for (uint8_t column = 0; column <=
row; ++column) {
75 measurement.
frame.
q = 2.5f;
76 measurement.frame.frameAngle = 0.3f;
77 measurement.frame.u = 0.8f;
78 measurement.frame.v = -0.45f;
79 measurement.covariance = {0.04f, 0.012f, 0.09f};
83constexpr float BarrelBz = 5.f;
88 descriptor.
kind = SurfaceKind::Cylinder;
89 descriptor.referenceCoordinate = 2.5f;
90 descriptor.material = material;
109 for (uint8_t column = 0; column <=
row; ++column) {
124 measurement.
frame = {-50.f, 0.8f, -0.45f, 0.f};
125 measurement.frame.
q = -50.f;
126 measurement.frame.u = 0.8f;
127 measurement.frame.v = -0.45f;
128 measurement.covariance = {0.04f, 0.f, 0.09f};
132constexpr float DiskBz = 5.f;
137 descriptor.
kind = SurfaceKind::Disk;
138 descriptor.referenceCoordinate = -50.f;
139 descriptor.material = material;
155 measurement.covariance = {0.04f, 0.f, 0.09f};
157 return Propagator::propagateToMeasurement(
state,
reference, surface, measurement, 0.f,
158 direction,
false, 0.f,
chi2,
false);
165 return propagateThroughMaterial(
state,
reference, budget, direction);
171 const std::array<double, 5>& p,
174 double x = p[0],
y = p[1],
z =
source.referenceCoordinate, phi = p[2];
175 if (
source.kind == SurfaceKind::Cylinder) {
176 x =
source.referenceCoordinate * std::cos(
double(
source.alpha)) - p[0] * std::sin(
double(
source.alpha));
177 y =
source.referenceCoordinate * std::sin(
double(
source.alpha)) + p[0] * std::cos(
double(
source.alpha));
179 phi =
source.alpha + std::asin(p[2]);
181 const double curvature = p[4] * bz * o2::constants::math::B2C;
182 auto pointAt = [&](
double path) {
183 const double halfAngle = curvature *
path / 2.;
184 const double sinc = halfAngle == 0. ? 1. : std::sin(halfAngle) / halfAngle;
185 return std::array<double, 3>{
x +
path * sinc * std::cos(phi + halfAngle),
186 y +
path * sinc * std::sin(phi + halfAngle),
z +
path * p[3]};
189 if (
target.kind == SurfaceKind::Disk) {
191 const auto position = pointAt(
path);
192 return {position[0], position[1], phi + curvature *
path, p[3], p[4]};
194 const double csA = std::cos(
double(
target.alpha)), snA = std::sin(
double(
target.alpha));
197 for (
int iteration = 0; iteration < 6; ++iteration) {
198 const auto position = pointAt(
path);
199 path -= (position[0] * csA + position[1] * snA -
target.referenceCoordinate) /
200 std::cos(phi + curvature *
path -
target.alpha);
202 const auto position = pointAt(
path);
203 return {-position[0] * snA + position[1] * csA, position[2],
204 std::sin(phi + curvature *
path -
target.alpha), p[3], p[4]};
211 const auto targetKind =
source.kind == SurfaceKind::Cylinder ? SurfaceKind::Disk : SurfaceKind::Cylinder;
212 BOOST_REQUIRE(Propagator::convertKind(
target, targetKind, bz));
213 double jacobian[5][5]{};
214 std::array<double, 5> nominal{};
215 std::copy(std::begin(
source.parameters), std::end(
source.parameters), nominal.begin());
216 constexpr double step = 1.e-5;
217 for (
int column = 0; column < 5; ++column) {
218 auto plus = nominal, minus = nominal;
219 plus[column] += step;
220 minus[column] -= step;
221 const auto high = intersectConversionPlane(
source, plus,
target, bz);
222 const auto low = intersectConversionPlane(
source, minus,
target, bz);
224 jacobian[
row][column] = (high[
row] - low[
row]) / (2. * step);
228 for (
int column = 0; column <=
row; ++column) {
230 for (
int i = 0;
i < 5; ++
i) {
231 for (
int j = 0;
j < 5; ++
j) {
235 const float actual =
target.covariance[packedCovarianceIndex(
row, column)];
236 BOOST_CHECK_SMALL(
double(actual) -
expected, 1.e-7 + 2.e-5 * std::abs(
expected));
248 for (
const float bz : {-5.f, 5.f}) {
249 for (
const float qOverPt : {-20.f, -1.f, -0.1f, -0.01f, -1.e-8f, 1.e-8f, 0.01f, 0.1f, 1.f, 20.f}) {
250 for (
const float dz : {-32.f, -1.4222f, -0.01f, 0.01f, 1.4222f, 32.f}) {
251 for (
const float tanl : {-10.f, 10.f}) {
252 BOOST_TEST_CONTEXT(
"bz=" << bz <<
" q/pT=" << qOverPt <<
" dz=" << dz <<
" tanl=" << tanl)
254 auto source = diskState();
256 source.parameters[2] = 0.7f;
257 source.parameters[3] = tanl;
258 source.parameters[4] = qOverPt;
259 std::fill(std::begin(
source.covariance), std::end(
source.covariance), 0.f);
260 source.covariance[packedCovarianceIndex(4, 4)] = 1.f;
262 plane.referenceCoordinate += dz;
263 std::array<double, 5> parameters{};
264 std::copy(std::begin(
source.parameters), std::end(
source.parameters), parameters.begin());
265 const auto expected = intersectConversionPlane(
source, parameters, plane, bz);
266 constexpr double step = 1.e-3;
267 auto plus = parameters, minus = parameters;
270 const auto high = intersectConversionPlane(
source, plus, plane, bz);
271 const auto low = intersectConversionPlane(
source, minus, plane, bz);
280 BOOST_REQUIRE(Propagator::propagateForward(direct, plane.referenceCoordinate, bz));
281 BOOST_REQUIRE(Propagator::propagateForward(referenced,
reference, plane.referenceCoordinate, bz));
283 const double positionTolerance = 2.e-7 * std::abs(
expected[
row]) + 1.e-12;
284 BOOST_CHECK_SMALL(
double(direct.parameters[
row]) -
expected[
row], positionTolerance);
285 BOOST_CHECK_SMALL(
double(referenced.parameters[
row]) -
expected[
row], positionTolerance);
287 for (
int column = 0; column <=
row; ++column) {
288 const auto index = packedCovarianceIndex(
row, column);
290 const double tolerance = 2.e-5 * std::abs(covariance) + 1.e-16;
291 BOOST_CHECK_SMALL(
double(direct.covariance[
index]) - covariance, tolerance);
292 BOOST_CHECK_SMALL(
double(referenced.covariance[
index]) - covariance, tolerance);
307 for (
const float bz : {-5.f, 5.f}) {
308 for (
const float halfAngle : {-0.5f, -0.2501f, -0.25f, -0.2499f, 0.2499f, 0.25f, 0.2501f, 0.5f}) {
309 for (
const float dz : {-32.f, 32.f}) {
310 for (
const float tanl : {-2.5f, 2.5f}) {
311 const float qOverPt = halfAngle / (0.5f * o2::constants::math::B2C * bz * dz / tanl);
312 BOOST_TEST_CONTEXT(
"bz=" << bz <<
" q/pT=" << qOverPt <<
" dz=" << dz <<
" tanl=" << tanl)
314 auto source = diskState();
316 source.parameters[2] = 0.7f;
317 source.parameters[3] = tanl;
318 source.parameters[4] = qOverPt;
319 std::fill(std::begin(
source.covariance), std::end(
source.covariance), 0.f);
320 source.covariance[packedCovarianceIndex(4, 4)] = 1.f;
322 plane.referenceCoordinate += dz;
323 std::array<double, 5> parameters{};
324 std::copy(std::begin(
source.parameters), std::end(
source.parameters), parameters.begin());
325 const auto expected = intersectConversionPlane(
source, parameters, plane, bz);
326 constexpr double step = 1.e-3;
327 auto plus = parameters, minus = parameters;
330 const auto high = intersectConversionPlane(
source, plus, plane, bz);
331 const auto low = intersectConversionPlane(
source, minus, plane, bz);
340 BOOST_REQUIRE(Propagator::propagateForward(direct, plane.referenceCoordinate, bz));
341 BOOST_REQUIRE(Propagator::propagateForward(referenced,
reference, plane.referenceCoordinate, bz));
346 const double path = double(dz) / tanl;
347 const double scale =
row < 2 ? std::abs(
path)
348 :
row == 2 ? std::abs(parameters[2]) + 2. * std::abs(
double(halfAngle))
350 const double positionTolerance = 4. * std::numeric_limits<float>::epsilon() * scale + 1.e-12;
351 BOOST_CHECK_SMALL(
double(direct.parameters[
row]) -
expected[
row], positionTolerance);
352 BOOST_CHECK_SMALL(
double(referenced.parameters[
row]) -
expected[
row], positionTolerance);
354 for (
int column = 0; column <=
row; ++column) {
355 const auto index = packedCovarianceIndex(
row, column);
357 const double tolerance = 2.e-5 * std::abs(covariance) + 1.e-16;
358 BOOST_CHECK_SMALL(
double(direct.covariance[
index]) - covariance, tolerance);
359 BOOST_CHECK_SMALL(
double(referenced.covariance[
index]) - covariance, tolerance);
371 for (
const float bz : {-5.f, 5.f}) {
372 for (
const float qOverPt : {-20.f, -0.1f, 0.1f, 20.f}) {
373 for (
const float dz : {-32.f, 32.f}) {
374 BOOST_TEST_CONTEXT(
"bz=" << bz <<
" q/pT=" << qOverPt <<
" dz=" << dz)
376 auto source = diskState();
377 source.parameters[4] = qOverPt;
379 plane.referenceCoordinate += dz;
380 std::array<double, 5> parameters{};
381 std::copy(std::begin(
source.parameters), std::end(
source.parameters), parameters.begin());
382 const auto expected = intersectConversionPlane(
source, parameters, plane, bz);
383 double jacobian[5][5]{};
384 constexpr double step = 1.e-5;
385 for (
int column = 0; column < 5; ++column) {
386 auto plus = parameters, minus = parameters;
387 plus[column] += step;
388 minus[column] -= step;
389 const auto high = intersectConversionPlane(
source, plus, plane, bz);
390 const auto low = intersectConversionPlane(
source, minus, plane, bz);
392 jacobian[
row][column] = (high[
row] - low[
row]) / (2. * step);
398 std::array<double, 5> difference{};
401 difference[
row] = double(referenced.parameters[
row]) -
source.parameters[
row];
403 BOOST_REQUIRE(Propagator::propagateForward(direct, plane.referenceCoordinate, bz));
404 BOOST_REQUIRE(Propagator::propagateForward(referenced,
reference, plane.referenceCoordinate, bz));
407 for (
int i = 0;
i < 5; ++
i) {
408 linearized += jacobian[
row][
i] * difference[
i];
410 BOOST_CHECK_SMALL(
double(direct.parameters[
row]) -
expected[
row], 2.e-6);
411 BOOST_CHECK_SMALL(
double(referenced.parameters[
row]) - linearized, 3.e-6);
412 for (
int column = 0; column <=
row; ++column) {
413 double covariance = 0.;
414 for (
int i = 0;
i < 5; ++
i) {
415 for (
int j = 0;
j < 5; ++
j) {
416 covariance += jacobian[
row][
i] *
source.covariance[packedCovarianceIndex(
i,
j)] * jacobian[column][
j];
419 const auto index = packedCovarianceIndex(
row, column);
420 const double tolerance = 1.e-7 + 2.e-5 * std::abs(covariance);
421 BOOST_CHECK_SMALL(
double(direct.covariance[
index]) - covariance, tolerance);
422 BOOST_CHECK_SMALL(
double(referenced.covariance[
index]) - covariance, tolerance);
435 auto state = barrelState();
436 auto linRef = barrelLinRef(
state);
437 const auto measurement = barrelMeasurement();
441 BOOST_REQUIRE(Propagator::propagateToMeasurement(
state, linRef, descriptor, measurement, BarrelBz,
442 material::MaterialTraversalDirection::AlongMomentum,
443 false, 0.f,
chi2,
false));
447 BOOST_CHECK_GE(
chi2, 0.f);
452 auto state = diskState();
453 auto linRef = diskLinRef(
state);
454 const auto measurement = diskMeasurement();
458 BOOST_REQUIRE(Propagator::propagateToMeasurement(
state, linRef, descriptor, measurement, DiskBz,
459 material::MaterialTraversalDirection::AlongMomentum,
460 false, 0.f,
chi2,
false));
464 BOOST_CHECK_GE(
chi2, 0.f);
469 auto fieldOn = diskState();
470 auto lowPositive = diskState();
471 auto lowNegative = diskState();
473 BOOST_REQUIRE(Propagator::propagateToReference(fieldOn, -50.f, 5.f));
474 BOOST_REQUIRE(Propagator::propagateToReference(lowPositive, -50.f, 0.01f));
475 BOOST_REQUIRE(Propagator::propagateToReference(lowNegative, -50.f, -0.01f));
484 auto viaPropagator = barrelState();
485 auto viaPropagatorRef = barrelLinRef(viaPropagator);
486 auto viaDirect = viaPropagator;
487 auto viaDirectRef = viaPropagatorRef;
488 const auto measurement = barrelMeasurement();
490 const auto descriptor = cylinderDescriptor(material);
491 float chi2Propagator = 0.f;
492 float chi2Direct = 0.f;
494 BOOST_REQUIRE(Propagator::propagateToMeasurement(viaPropagator, viaPropagatorRef, descriptor, measurement, BarrelBz,
495 material::MaterialTraversalDirection::OppositeMomentum,
496 false, 0.f, chi2Propagator,
true));
498 BOOST_REQUIRE(Propagator::rotateBarrel(viaDirect, viaDirectRef, measurement.frame.frameAngle, BarrelBz));
499 BOOST_REQUIRE(Propagator::propagateBarrel(viaDirect, viaDirectRef, measurement.frame.q, BarrelBz));
500 float predChi2 = 0.f;
501 BOOST_REQUIRE(Propagator::predictedChi2Barrel(viaDirect, measurement, predChi2));
502 float updateChi2 = 0.f;
503 BOOST_REQUIRE(Propagator::updateBarrel(viaDirect, measurement, updateChi2));
504 chi2Direct = updateChi2;
505 BOOST_REQUIRE(Propagator::shiftReferenceToMeasurementBarrel(viaDirectRef, measurement));
508 BOOST_CHECK(bitEqual(viaPropagatorRef, viaDirectRef));
514 auto state = barrelState();
517 const auto original =
state;
520 const float snp = original.parameters[2];
521 const float tgl = original.parameters[3];
522 const float incidenceScale = std::sqrt((1.f + tgl * tgl) / ((1.f - snp) * (1.f + snp)));
524 nominalMaterial.
xOverX0 * incidenceScale,
525 nominalMaterial.arealDensityGPerCm2 * incidenceScale};
526 const float transverseMomentum =
static_cast<float>(original.absCharge) / std::abs(original.parameters[4]);
527 const float momentum = transverseMomentum * std::sqrt(1.f + tgl * tgl);
529 float expectedMomentum = 0.f;
530 float expectedTheta2 = 0.f;
531 float expectedVariance = 0.f;
533 material::MaterialTraversalDirection::AlongMomentum,
534 legacyMaterial, expectedMomentum, expectedTheta2, expectedVariance);
536 float uncorrectedMomentum = 0.f;
537 float uncorrectedTheta2 = 0.f;
538 float uncorrectedVariance = 0.f;
540 material::MaterialTraversalDirection::AlongMomentum,
541 nominalMaterial, uncorrectedMomentum, uncorrectedTheta2, uncorrectedVariance);
542 const auto result = propagateThroughMaterial(
state, nominalMaterial,
543 material::MaterialTraversalDirection::AlongMomentum);
546 BOOST_REQUIRE(uncorrected);
550 BOOST_CHECK_GT(expectedTheta2, uncorrectedTheta2);
551 BOOST_CHECK_LT(expectedMomentum, uncorrectedMomentum);
556 auto state = barrelState();
559 auto linRef = barrelLinRef(
state);
560 linRef.parameters[2] = 0.6f;
561 linRef.parameters[3] = 1.2f;
563 const float referenceQ2PtBefore = linRef.parameters[4];
566 const float snp = linRef.parameters[2];
567 const float tgl = linRef.parameters[3];
568 const float incidenceScale = std::sqrt((1.f + tgl * tgl) / ((1.f - snp) * (1.f + snp)));
570 nominalMaterial.
xOverX0 * incidenceScale,
571 nominalMaterial.arealDensityGPerCm2 * incidenceScale};
574 const float momentum = transverseMomentum * std::sqrt(1.f + stateTgl * stateTgl);
576 float expectedMomentum = 0.f;
577 float expectedTheta2 = 0.f;
578 float expectedVariance = 0.f;
580 material::MaterialTraversalDirection::AlongMomentum,
581 legacyMaterial, expectedMomentum, expectedTheta2, expectedVariance);
582 const auto result = propagateThroughMaterial(
state, linRef, nominalMaterial,
583 material::MaterialTraversalDirection::AlongMomentum);
588 const float expectedStateQ2Pt = (stateQ2PtBefore * momentum) / expectedMomentum;
589 const float expectedReferenceQ2Pt = (referenceQ2PtBefore * momentum) / expectedMomentum;
596 auto state = barrelState();
597 auto linRef = barrelLinRef(
state);
598 const auto referenceBefore = linRef;
600 const auto result = propagateThroughMaterial(
602 material::MaterialTraversalDirection::AlongMomentum);
611 auto state = barrelState();
612 auto linRef = barrelLinRef(
state);
613 const auto stateBefore =
state;
614 const auto referenceBefore = linRef;
616 const auto result = propagateThroughMaterial(
618 material::MaterialTraversalDirection::AlongMomentum);
628 auto viaPropagator = diskState();
629 auto viaPropagatorRef = diskLinRef(viaPropagator);
630 auto viaDirect = viaPropagator;
631 auto viaDirectRef = viaPropagatorRef;
632 const auto measurement = diskMeasurement();
634 const auto descriptor = diskDescriptor(material);
635 float chi2Propagator = 0.f;
636 float chi2Direct = 0.f;
638 BOOST_REQUIRE(Propagator::propagateToMeasurement(viaPropagator, viaPropagatorRef, descriptor, measurement, DiskBz,
639 material::MaterialTraversalDirection::OppositeMomentum,
640 false, 0.f, chi2Propagator,
true));
642 BOOST_REQUIRE(Propagator::propagateForward(viaDirect, viaDirectRef, measurement.frame.q, DiskBz));
643 float predChi2 = 0.f;
644 BOOST_REQUIRE(Propagator::predictedChi2Forward(viaDirect, measurement, predChi2));
645 float updateChi2 = 0.f;
646 BOOST_REQUIRE(Propagator::updateForward(viaDirect, measurement, updateChi2));
647 chi2Direct = updateChi2;
648 BOOST_REQUIRE(Propagator::shiftReferenceToMeasurementForward(viaDirectRef, measurement));
651 BOOST_CHECK(bitEqual(viaPropagatorRef, viaDirectRef));
657 auto state = diskState();
659 const auto original =
state;
662 const float tgl = original.parameters[3];
663 const float incidenceScale = std::sqrt(1.f + tgl * tgl) / std::abs(tgl);
665 nominalMaterial.
xOverX0 * incidenceScale,
666 nominalMaterial.arealDensityGPerCm2 * incidenceScale};
667 const float transverseMomentum =
static_cast<float>(original.absCharge) / std::abs(original.parameters[4]);
668 const float momentum = transverseMomentum * std::sqrt(1.f + tgl * tgl);
670 float expectedMomentum = 0.f;
671 float expectedTheta2 = 0.f;
672 float expectedVariance = 0.f;
674 material::MaterialTraversalDirection::AlongMomentum,
675 legacyMaterial, expectedMomentum, expectedTheta2, expectedVariance);
677 float uncorrectedMomentum = 0.f;
678 float uncorrectedTheta2 = 0.f;
679 float uncorrectedVariance = 0.f;
681 material::MaterialTraversalDirection::AlongMomentum,
682 nominalMaterial, uncorrectedMomentum, uncorrectedTheta2, uncorrectedVariance);
683 const auto result = propagateThroughMaterial(
state, nominalMaterial,
684 material::MaterialTraversalDirection::AlongMomentum);
687 BOOST_REQUIRE(uncorrected);
691 BOOST_CHECK_GT(expectedTheta2, uncorrectedTheta2);
692 BOOST_CHECK_LT(expectedMomentum, uncorrectedMomentum);
697 auto state = diskState();
698 auto linRef = diskLinRef(
state);
699 linRef.parameters[3] = -0.5f;
701 const float referenceQ2PtBefore = linRef.parameters[4];
704 const float referenceTgl = linRef.parameters[3];
705 const float incidenceScale = std::sqrt(1.f + referenceTgl * referenceTgl) / std::abs(referenceTgl);
707 nominalMaterial.
xOverX0 * incidenceScale,
708 nominalMaterial.arealDensityGPerCm2 * incidenceScale};
711 const float momentum = transverseMomentum * std::sqrt(1.f + stateTgl * stateTgl);
713 float expectedMomentum = 0.f;
714 float expectedTheta2 = 0.f;
715 float expectedVariance = 0.f;
717 material::MaterialTraversalDirection::AlongMomentum,
718 scaledMaterial, expectedMomentum, expectedTheta2, expectedVariance);
719 const auto result = propagateThroughMaterial(
state, linRef, nominalMaterial,
720 material::MaterialTraversalDirection::AlongMomentum);
725 const float expectedStateQ2Pt = (stateQ2PtBefore * momentum) / expectedMomentum;
726 const float expectedReferenceQ2Pt = (referenceQ2PtBefore * momentum) / expectedMomentum;
733 auto state = diskState();
734 auto linRef = diskLinRef(
state);
735 const auto referenceBefore = linRef;
737 const auto result = propagateThroughMaterial(
739 material::MaterialTraversalDirection::AlongMomentum);
748 auto state = diskState();
749 auto linRef = diskLinRef(
state);
750 const auto stateBefore =
state;
751 const auto referenceBefore = linRef;
753 const auto result = propagateThroughMaterial(
755 material::MaterialTraversalDirection::AlongMomentum);
765 for (
const auto original : {barrelState(), diskState()}) {
766 auto state = original;
771 material::MaterialTraversalDirection::AlongMomentum));
781 auto state = barrelState();
782 auto linRef = barrelLinRef(
state);
783 const auto poisonState =
state;
787 measurement.
frame.
q = -10.f;
788 measurement.frame.u = 5.f;
789 measurement.frame.v = -5.f;
790 measurement.covariance = {10.f, 0.f, 10.f};
794 const bool ok = Propagator::propagateToMeasurement(
state, linRef, descriptor, measurement, BarrelBz,
795 material::MaterialTraversalDirection::AlongMomentum,
796 false, 0.f,
chi2,
false);
812 auto nominalState = barrelState();
813 auto nominalRef = barrelLinRef(nominalState);
814 auto perturbedState = nominalState;
815 auto perturbedRef = nominalRef;
816 perturbedRef.parameters[0] += 0.1f;
817 perturbedRef.parameters[1] -= 0.2f;
818 perturbedRef.parameters[2] += 0.01f;
819 perturbedRef.parameters[3] -= 0.02f;
820 perturbedRef.parameters[4] += 0.001f;
823 measurement.
frame.
q = -10.f;
824 measurement.frame.u = 5.f;
825 measurement.frame.v = -5.f;
826 measurement.covariance = {10.f, 0.f, 10.f};
828 float nominalChi2 = 0.f;
829 float perturbedChi2 = 0.f;
831 BOOST_REQUIRE(Propagator::propagateToMeasurement(nominalState, nominalRef, descriptor, measurement, BarrelBz,
832 material::MaterialTraversalDirection::AlongMomentum,
833 false, 0.f, nominalChi2,
false));
834 BOOST_REQUIRE(Propagator::propagateToMeasurement(perturbedState, perturbedRef, descriptor, measurement, BarrelBz,
835 material::MaterialTraversalDirection::AlongMomentum,
836 false, 0.f, perturbedChi2,
false));
838 BOOST_CHECK(bitEqual(perturbedState, nominalState));
845 auto nominalState = diskState();
846 auto nominalRef = diskLinRef(nominalState);
847 auto perturbedState = nominalState;
848 auto perturbedRef = nominalRef;
849 perturbedRef.parameters[0] += 0.1f;
850 perturbedRef.parameters[1] -= 0.2f;
851 perturbedRef.parameters[2] += 0.01f;
852 perturbedRef.parameters[3] -= 0.02f;
853 perturbedRef.parameters[4] += 0.001f;
855 const auto measurement = barrelMeasurement();
857 float nominalChi2 = 0.f;
858 float perturbedChi2 = 0.f;
860 BOOST_REQUIRE(Propagator::propagateToMeasurement(nominalState, nominalRef, descriptor, measurement, DiskBz,
861 material::MaterialTraversalDirection::AlongMomentum,
862 false, 0.f, nominalChi2,
false));
863 BOOST_REQUIRE(Propagator::propagateToMeasurement(perturbedState, perturbedRef, descriptor, measurement, DiskBz,
864 material::MaterialTraversalDirection::AlongMomentum,
865 false, 0.f, perturbedChi2,
false));
867 BOOST_CHECK(bitEqual(perturbedState, nominalState));
874 for (
const float bz : {-5.f, 0.f, 5.f}) {
875 for (
const float sign : {-1.f, 1.f}) {
876 auto barrel = barrelState();
877 barrel.parameters[3] *= sign;
878 barrel.parameters[4] *= sign;
879 checkConversionCovariance(barrel, bz);
880 auto disk = diskState();
881 disk.parameters[3] *= sign;
882 disk.parameters[4] *= sign;
883 checkConversionCovariance(disk, bz);
890 auto state = barrelState();
898 const auto before =
state;
900 BOOST_REQUIRE(Propagator::convertKind(
state, SurfaceKind::Disk, 5.f));
901 BOOST_CHECK_CLOSE(
state.
covariance[packedCovarianceIndex(0, 0)], 0.25f, 1.e-4f);
902 const float curvature = before.parameters[4] * 5.f * o2::constants::math::B2C;
903 BOOST_CHECK_CLOSE(
state.
covariance[packedCovarianceIndex(2, 0)], curvature / 4.f, 1.e-4f);
904 BOOST_REQUIRE(Propagator::convertKind(
state, SurfaceKind::Cylinder, 5.f));
905 for (
int i = 0;
i < 15; ++
i) {
912 for (
const float tanl : {0.f, std::numeric_limits<float>::quiet_NaN(), std::numeric_limits<float>::infinity()}) {
913 auto state = barrelState();
915 const auto before =
state;
925 for (
const bool startOnDisk : {
false,
true}) {
926 const auto source = startOnDisk ? diskState() : barrelState();
927 const auto target = startOnDisk ? cylinderDescriptor({0.f, 0.f}) : diskDescriptor({0.f, 0.f});
930 BOOST_REQUIRE(Propagator::convertKind(converted,
target.kind, 0.f));
932 measurement.
frame = {converted.referenceCoordinate, converted.parameters[0], converted.parameters[1], converted.alpha};
933 measurement.covariance = {0.04f, 0.f, 0.04f};
936 BOOST_REQUIRE(Propagator::attachMeasurement(
state,
target, measurement, 0.f,
937 material::MaterialTraversalDirection::OppositeMomentum,
940 for (
int i = 0;
i < 5; ++
i) {
943 BOOST_CHECK_SMALL(
chi2, 1.e-5f);
947 measurement.frame.u += 10.f;
951 material::MaterialTraversalDirection::OppositeMomentum,
952 true, 1.e-6f,
chi2));
961 auto state = barrelState(2, o2::track::PID::Kaon);
963 BOOST_REQUIRE(Propagator::convertKind(
state, SurfaceKind::Disk, BarrelBz));
971 auto state = barrelState();
972 const auto before =
state;
974 BOOST_REQUIRE(Propagator::convertKind(
state, SurfaceKind::Cylinder, DiskBz));
982 auto state = diskState();
985 const auto poison =
state;
987 BOOST_CHECK(!Propagator::convertKind(
state, SurfaceKind::Cylinder, DiskBz));
994 for (
const float phi : {o2::constants::math::PI, -2.f, 2.f, o2::constants::math::PIHalf}) {
995 auto state = diskState();
999 const auto before =
state;
1001 BOOST_CHECK(!Propagator::convertKind(
state, SurfaceKind::Cylinder, DiskBz));
1011 auto state = barrelState();
1012 auto linRef = barrelLinRef(
state);
1013 const auto measurement = barrelMeasurement();
1017 BOOST_REQUIRE(Propagator::propagateToMeasurement(
state, linRef, descriptor, measurement, BarrelBz,
1018 material::MaterialTraversalDirection::AlongMomentum,
1019 false, 0.f,
chi2,
false));
1024 auto zeroState = barrelState();
1025 auto zeroRef = barrelLinRef(zeroState);
1026 auto materialState = barrelState();
1027 auto materialRef = barrelLinRef(materialState);
1028 const auto measurement = barrelMeasurement();
1031 float zeroChi2 = 0.f;
1032 float materialChi2 = 0.f;
1034 BOOST_REQUIRE(Propagator::propagateToMeasurement(zeroState, zeroRef, zeroDescriptor, measurement, BarrelBz,
1035 material::MaterialTraversalDirection::OppositeMomentum,
1036 false, 0.f, zeroChi2,
false));
1037 BOOST_REQUIRE(Propagator::propagateToMeasurement(materialState, materialRef, materialDescriptor, measurement, BarrelBz,
1038 material::MaterialTraversalDirection::OppositeMomentum,
1039 false, 0.f, materialChi2,
false));
1051 auto state = barrelState();
1052 auto linRef = barrelLinRef(
state);
1053 const auto measurement = barrelMeasurement();
1061 std::array<detail::RefitMeasurementSlot, 3> slots{hole, present, hole};
1063 uint32_t acceptedHitCount = 999;
1066 material::MaterialTraversalDirection::AlongMomentum,
false, 100.f));
1073 for (
const auto direction : {material::MaterialTraversalDirection::AlongMomentum,
1074 material::MaterialTraversalDirection::OppositeMomentum}) {
1075 const bool alongMomentum = direction == material::MaterialTraversalDirection::AlongMomentum;
1076 auto state = diskState();
1080 for (uint8_t column = 0; column <
row; ++column) {
1084 auto linRef = diskLinRef(
state);
1086 const float momentumScale = std::sqrt(1.f + tanl * tanl);
1087 float expectedMomentum = momentumScale / std::abs(
state.
parameters[4]);
1088 const float initialMomentum = expectedMomentum;
1089 constexpr float expectedSurfaceX0 = 0.0084f;
1090 const float pathX0 = expectedSurfaceX0 * momentumScale / std::abs(tanl);
1093 std::array<detail::RefitMeasurementSlot, MFTNLayers> slots{};
1095 const auto layer =
static_cast<uint16_t
>(alongMomentum ? hit :
MFTNLayers - 1 - hit);
1096 auto& slot = slots[hit];
1098 slot.present =
true;
1101 slot.measurement.frame = {
z,
1104 slot.measurement.covariance = {0.04f, 0.f, 0.04f};
1106 float resultMomentum = 0.f;
1107 float resultTheta2 = 0.f;
1108 float resultVariance = 0.f;
1110 direction, expectedMaterial, resultMomentum, resultTheta2, resultVariance);
1112 expectedMomentum = resultMomentum;
1115 uint32_t acceptedHitCount = 0;
1118 direction,
false, 100.f));
1120 BOOST_CHECK_CLOSE(momentumScale / std::abs(
state.
parameters[4]), expectedMomentum, 1.e-4f);
1121 BOOST_CHECK(alongMomentum ? expectedMomentum < initialMomentum : expectedMomentum > initialMomentum);
1129 for (
const bool forward : {
false,
true}) {
1130 for (
const bool negativeU : {
false,
true}) {
1133 for (
const float variance : {-1.f, -1.e-6f}) {
1134 BOOST_TEST_CONTEXT(
"forward=" << forward <<
", negativeU=" << negativeU <<
", variance=" << variance)
1136 auto state = forward ? diskState() : barrelState();
1137 const auto before =
state;
1138 auto measurement = forward ? diskMeasurement() : barrelMeasurement();
1139 (negativeU ? measurement.covariance.uu : measurement.covariance.vv) = variance;
1143 : Propagator::predictedChi2Barrel(
state, measurement,
chi2)));
1146 : Propagator::updateBarrel(
state, measurement,
chi2)));
1157 auto state = barrelState();
1158 auto linRef = barrelLinRef(
state);
1159 const auto poisonState =
state;
1160 const auto poisonRef = linRef;
1161 auto measurement = barrelMeasurement();
1162 measurement.frame.u += 5.f;
1165 const float poisonChi2 =
chi2;
1167 const bool ok = Propagator::propagateToMeasurement(
state, linRef, descriptor, measurement, BarrelBz,
1168 material::MaterialTraversalDirection::AlongMomentum,
1169 true, 1.e-6f,
chi2,
false);
1179 auto state = barrelState();
1180 auto linRef = barrelLinRef(
state);
1181 const auto poisonState =
state;
1182 const auto measurement = barrelMeasurement();
1189 const bool ok = Propagator::propagateToMeasurement(
state, linRef, descriptor, measurement, BarrelBz,
1190 material::MaterialTraversalDirection::AlongMomentum,
1191 false, 0.f,
chi2,
false);
std::array< float, NCoordinates > derivative
GLsizei GLsizei GLchar * source
GLsizei const GLfloat * value
GLsizei const GLchar *const * path
GLenum GLuint GLint GLint layer
GLdouble GLdouble GLdouble z
bool driveRefitLeg(SurfaceTrackState &state, SurfaceTrackParameters &linRef, float &chi2, uint32_t &acceptedHitCount, gsl::span< const RefitMeasurementSlot > orderedSlots, SurfaceCatalogView surfaceCatalog, float bz, material::MaterialTraversalDirection direction, bool shiftReferenceToMeasurement, float maxChi2) noexcept
bool calculateMaterialPhysics(float momentumGeV, o2::track::PID pid, uint8_t absCharge, MaterialTraversalDirection direction, IntegratedMaterialBudget material, float &momentumAfterGeV, float &highlandTheta2Rad2, float &relativeInverseMomentumVariance) noexcept
MaterialTraversalDirection
constexpr std::array< SurfaceDescriptor, MFTNLayers > kMFTSurfaces
constexpr int MFTNLayers
MFT CA half-disk layer count.
float referenceCoordinate
float arealDensityGPerCm2
crossed length*density, g/cm^2
float xOverX0
thickness in units of radiation length
std::map< std::string, ID > expected
BOOST_AUTO_TEST_CASE(ForwardHelixSmallAngleMomentumDerivative)
BOOST_CHECK_EQUAL(triggersD.size(), triggers.size())