8#include <framework/dataobjects/Helix.h>
10#include <Math/VectorUtil.h>
11#include <Math/Vector2D.h>
12#include <Math/Vector3D.h>
16#include <framework/utilities/TestHelpers.h>
18#include <gtest/gtest.h>
22using namespace HelixParameterIndex;
25std::ostream& operator<<(::std::ostream& output,
const ROOT::Math::XYZVector& vector3)
28 <<
"ROOT::Math::XYZVector("
29 << vector3.X() <<
", "
30 << vector3.Y() <<
", "
31 << vector3.Z() <<
")";
45 bool d0Near = fabs(expected.getD0() - actual.getD0()) < tolerance;
46 bool phi0Near =
angleNear(expected.getPhi0(), actual.getPhi0(), tolerance);
47 bool omegaNear = fabs(expected.getOmega() - actual.getOmega()) < tolerance;
48 bool z0Near = fabs(expected.getZ0() - actual.getZ0()) < tolerance;
49 bool tanLambdaNear = fabs(expected.getTanLambda() - actual.getTanLambda()) < tolerance;
51 return d0Near and phi0Near and omegaNear and z0Near and tanLambdaNear;
56 Belle2::Helix helixFromCenter(
const ROOT::Math::XYZVector& center,
const float& radius,
const float& tanLambda)
58 double omega = 1 / radius;
59 double phi0 = center.Phi() + copysign(M_PI / 2.0, radius);
60 double d0 = copysign(center.Rho(), radius) - radius;
61 double z0 = center.Z();
67 vector<float> linspace(
const float& start,
const float& end,
const int n)
69 std::vector<float> result(n);
73 for (
int i = 1; i < n - 1; ++i) {
74 float start_weight = (float)(n - 1 - i) / (n - 1);
75 float end_weight = 1 - start_weight;
76 result[i] = start * start_weight + end * end_weight;
83 class HelixTest :
public ::testing::Test {
87 double absError = 1e-6;
88 double nominalBz = 1.5;
90 std::vector<float> omegas { -1, 0, 1};
92 std::vector<float> phi0s = linspace(-M_PI, M_PI, 11);
93 std::vector<float> d0s { -0.5, -0.2, 0, 0.2, 0.5};
95 std::vector<float> chis = linspace(-5 * M_PI / 6, 5 * M_PI / 6, 11);
97 std::vector<ROOT::Math::XYZVector> bys = {
98 ROOT::Math::XYZVector(-2.0, 0.5, 0.0),
99 ROOT::Math::XYZVector(-1.0, 0.5, 0.0),
100 ROOT::Math::XYZVector(0.0, 0.5, 0.0),
101 ROOT::Math::XYZVector(1.0, 0.5, 0.0),
102 ROOT::Math::XYZVector(2.0, 0.5, 0.0),
104 ROOT::Math::XYZVector(-2.0, 0.0, 0.0),
105 ROOT::Math::XYZVector(-1.0, 0.0, 0.0),
106 ROOT::Math::XYZVector(0.0, 0.0, 0.0),
107 ROOT::Math::XYZVector(1.0, 0.0, 0.0),
108 ROOT::Math::XYZVector(2.0, 0.0, 0.0),
110 ROOT::Math::XYZVector(-2.0, -1.0, 0.0),
111 ROOT::Math::XYZVector(-1.0, -1.0, 0.0),
112 ROOT::Math::XYZVector(0.0, -1.0, 0.0),
113 ROOT::Math::XYZVector(1.0, -1.0, 0.0),
114 ROOT::Math::XYZVector(2.0, -1.0, 0.0),
120 TEST_F(HelixTest, Getters)
123 unsigned int nCases = 1;
124 double bField = nominalBz;
126 for (
unsigned int i = 0; i < nCases; ++i) {
128 short int charge = generator.Uniform(-1, 1) > 0 ? 1 : -1;
131 ROOT::Math::XYVector d(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
132 ROOT::Math::XYVector pt(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
133 d.SetCoordinates(d.X(), -d.X() * pt.X() / pt.Y());
136 ROOT::Math::XYZVector position(d.X(), d.Y(), generator.Uniform(-1, 1));
137 ROOT::Math::XYZVector momentum(pt.X(), pt.Y(), generator.Uniform(-1, 1));
140 Helix helix(position, momentum, charge, bField);
143 EXPECT_ALL_NEAR(position, helix.getPerigee(), absError);
144 EXPECT_ALL_NEAR(momentum, helix.getMomentum(bField), absError);
147 EXPECT_NEAR(momentum.Rho(), helix.getTransverseMomentum(bField), absError);
150 EXPECT_NEAR(charge / momentum.Rho(), helix.getKappa(bField), absError);
154 EXPECT_NEAR(position.Rho(), fabs(helix.getD0()), absError);
157 EXPECT_SAME_SIGN(position.Cross(momentum).Z(), helix.getD0());
160 EXPECT_NEAR(momentum.Phi(), helix.getPhi0(), absError);
163 EXPECT_NEAR(position.Z(), helix.getZ0(), absError);
166 EXPECT_NEAR(1 / tan(momentum.Theta()), helix.getTanLambda(), absError);
169 EXPECT_NEAR(1 / tan(momentum.Theta()), helix.getCotTheta(), absError);
172 EXPECT_EQ(charge, helix.getChargeSign());
177 TEST_F(HelixTest, SignOfD0)
181 const ROOT::Math::XYZVector position(1, 0, 0);
182 const ROOT::Math::XYZVector momentum(0, 1, 0);
183 const ROOT::Math::XYZVector oppositeMomentum(0, -1, 0);
185 const float bField = nominalBz;
187 Helix helix(position, momentum, charge, bField);
188 EXPECT_NEAR(1, helix.getD0(), absError);
191 Helix helix2(position, momentum, -charge, bField);
192 EXPECT_NEAR(1, helix2.getD0(), absError);
195 Helix oppositeMomentumHelix(position, oppositeMomentum, charge, bField);
196 EXPECT_NEAR(-1, oppositeMomentumHelix.getD0(), absError);
198 Helix oppositeMomentumHelix2(position, oppositeMomentum, -charge, bField);
199 EXPECT_NEAR(-1, oppositeMomentumHelix2.getD0(), absError);
203 TEST_F(HelixTest, Center)
211 ROOT::Math::XYZVector center(0.0, -2.0, 0.0);
216 Helix helix = helixFromCenter(center, radius, tanLambda);
218 ROOT::Math::XYZVector actualCenter = helix.getPerigee() * ((1 / helix.getOmega() + helix.getD0()) / helix.getD0());
219 EXPECT_NEAR(center.X(), actualCenter.X(), absError);
220 EXPECT_NEAR(center.Y(), actualCenter.Y(), absError);
223 TEST_F(HelixTest, Explicit)
231 ROOT::Math::XYZVector center(0.0, -2.0, 0.0);
236 Helix helix = helixFromCenter(center, radius, tanLambda);
237 EXPECT_NEAR(-1, helix.getD0(), absError);
238 EXPECT_ANGLE_NEAR(-M_PI, helix.getPhi0(), absError);
239 EXPECT_NEAR(-1, helix.getOmega(), absError);
244 float arcLength2D = 0;
245 ROOT::Math::XYZVector position = helix.getPositionAtArcLength2D(arcLength2D);
246 ROOT::Math::XYZVector tangential = helix.getUnitTangentialAtArcLength2D(arcLength2D);
248 EXPECT_ALL_NEAR(ROOT::Math::XYZVector(0.0, -1.0, 0.0), position, absError);
249 EXPECT_ANGLE_NEAR(-M_PI, tangential.Phi(), absError);
253 float arcLength2D = M_PI / 2;
254 ROOT::Math::XYZVector position = helix.getPositionAtArcLength2D(arcLength2D);
255 ROOT::Math::XYZVector tangential = helix.getUnitTangentialAtArcLength2D(arcLength2D);
256 EXPECT_ALL_NEAR(ROOT::Math::XYZVector(-1.0, -2.0, 0.0), position, absError);
257 EXPECT_ANGLE_NEAR(-M_PI / 2, tangential.Phi(), absError);
261 float arcLength2D = M_PI;
262 ROOT::Math::XYZVector position = helix.getPositionAtArcLength2D(arcLength2D);
263 ROOT::Math::XYZVector tangential = helix.getUnitTangentialAtArcLength2D(arcLength2D);
264 EXPECT_ALL_NEAR(ROOT::Math::XYZVector(0.0, -3.0, 0.0), position, absError);
265 EXPECT_ANGLE_NEAR(0, tangential.Phi(), absError);
269 float arcLength2D = 3 * M_PI / 2 ;
270 ROOT::Math::XYZVector position = helix.getPositionAtArcLength2D(arcLength2D);
271 ROOT::Math::XYZVector tangential = helix.getUnitTangentialAtArcLength2D(arcLength2D);
272 EXPECT_ALL_NEAR(ROOT::Math::XYZVector(1.0, -2.0, 0.0), position, absError);
273 EXPECT_ANGLE_NEAR(M_PI / 2, tangential.Phi(), absError);
277 TEST_F(HelixTest, Tangential)
282 for (
const float d0 : d0s) {
283 for (
const float phi0 : phi0s) {
284 for (
const float omega : omegas) {
286 Helix helix(d0, phi0, omega, z0, tanLambda);
287 TEST_CONTEXT(
"Failed for " << helix);
289 ROOT::Math::XYZVector tangentialAtPerigee = helix.getUnitTangentialAtArcLength2D(0.0);
291 EXPECT_ANGLE_NEAR(phi0, tangentialAtPerigee.Phi(), absError);
292 EXPECT_FLOAT_EQ(1.0, tangentialAtPerigee.R());
293 EXPECT_FLOAT_EQ(tanLambda, 1 / tan(tangentialAtPerigee.Theta()));
295 for (
const float chi : chis) {
299 float arcLength2D = chi;
302 ROOT::Math::XYZVector tangential = helix.getUnitTangentialAtArcLength2D(arcLength2D);
303 EXPECT_ALL_NEAR(tangentialAtPerigee, tangential, absError);
306 float arcLength2D = -chi / omega;
307 ROOT::Math::XYZVector tangential = helix.getUnitTangentialAtArcLength2D(arcLength2D);
309 float actualChi = ROOT::Math::VectorUtil::DeltaPhi(tangentialAtPerigee, tangential);
310 EXPECT_ANGLE_NEAR(chi, actualChi, absError);
311 EXPECT_FLOAT_EQ(tangentialAtPerigee.Theta(), tangential.Theta());
312 EXPECT_FLOAT_EQ(1, tangential.R());
323 TEST_F(HelixTest, MomentumExtrapolation)
326 float tanLambda = -2;
328 for (
const float d0 : d0s) {
329 for (
const float phi0 : phi0s) {
330 for (
const float omega : omegas) {
333 Helix helix(d0, phi0, omega, z0, tanLambda);
334 ROOT::Math::XYZVector momentumAtPerigee = helix.getMomentum(nominalBz);
335 for (
const float chi : chis) {
337 float arcLength2D = -chi / omega;
338 ROOT::Math::XYZVector extrapolatedMomentum = helix.getMomentumAtArcLength2D(arcLength2D, nominalBz);
340 float actualChi = ROOT::Math::VectorUtil::DeltaPhi(momentumAtPerigee, extrapolatedMomentum);
341 EXPECT_ANGLE_NEAR(chi, actualChi, absError);
342 EXPECT_FLOAT_EQ(momentumAtPerigee.Theta(), extrapolatedMomentum.Theta());
343 EXPECT_FLOAT_EQ(momentumAtPerigee.R(), extrapolatedMomentum.R());
353 TEST_F(HelixTest, Extrapolation)
360 for (
const float d0 : d0s) {
361 for (
const float phi0 : phi0s) {
362 for (
const float omega : omegas) {
364 Helix helix(d0, phi0, omega, z0, tanLambda);
365 ROOT::Math::XYZVector perigee = helix.getPerigee();
367 ROOT::Math::XYZVector tangentialAtPerigee = helix.getUnitTangentialAtArcLength2D(0.0);
368 TEST_CONTEXT(
"Failed for " << helix);
372 for (
const float chi : chis) {
373 TEST_CONTEXT(
"Failed for chi = " << chi);
377 float expectedArcLength2D = omega != 0 ? -chi / omega : chi;
378 ROOT::Math::XYZVector pointOnHelix = helix.getPositionAtArcLength2D(expectedArcLength2D);
380 float cylindricalR = pointOnHelix.Rho();
381 float arcLength2D = helix.getArcLength2DAtCylindricalR(cylindricalR);
384 EXPECT_NEAR(fabs(expectedArcLength2D), arcLength2D, absError);
387 ROOT::Math::XYZVector secantVector = pointOnHelix - perigee;
389 if (expectedArcLength2D == 0) {
390 EXPECT_NEAR(0, secantVector.R(), absError);
392 ROOT::Math::XYVector secantVectorXY(secantVector.X(), secantVector.Y());
394 ROOT::Math::XYVector tangentialXY(tangentialAtPerigee.X(), tangentialAtPerigee.Y());
395 float coalignment = secantVectorXY.Dot(tangentialXY);
397 bool extrapolationIsForward = coalignment > 0;
398 bool expectedIsForward = expectedArcLength2D > 0;
399 EXPECT_EQ(expectedIsForward, extrapolationIsForward);
408 TEST_F(HelixTest, ExtrapolationToNormalPlane)
411 ROOT::Math::XYZVector center(0.0, 2.0, 0.0);
415 Helix helix = helixFromCenter(center, radius, tanLambda);
422 double arcLength2D = helix.getArcLength2DAtNormalPlane(x, y, nx, ny);
423 EXPECT_NEAR(-M_PI / 2, arcLength2D, absError);
427 ROOT::Math::XYZVector center(0.0, 2.0, 0.0);
431 Helix helix = helixFromCenter(center, radius, tanLambda);
438 double arcLength2D = helix.getArcLength2DAtNormalPlane(x, y, nx, ny);
439 EXPECT_NEAR(M_PI / 2, arcLength2D, absError);
443 ROOT::Math::XYZVector center(0.0, 2.0, 0.0);
447 Helix helix = helixFromCenter(center, radius, tanLambda);
454 double arcLength2D = helix.getArcLength2DAtNormalPlane(x, y, nx, ny);
455 EXPECT_NEAR(M_PI / 2, arcLength2D, absError);
459 ROOT::Math::XYZVector center(0.0, 2.0, 0.0);
463 Helix helix = helixFromCenter(center, radius, tanLambda);
470 double arcLength2D = helix.getArcLength2DAtNormalPlane(x, y, nx, ny);
471 EXPECT_NEAR(-M_PI / 2, arcLength2D, absError);
478 TEST_F(HelixTest, PerigeeExtrapolateRoundTrip)
481 float tanLambda = -2;
483 for (
const float d0 : d0s) {
484 for (
const float phi0 : phi0s) {
485 for (
const float omega : omegas) {
489 Helix expectedHelix(d0, phi0, omega, z0, tanLambda);
491 for (
const float chi : chis) {
492 float arcLength2D = -chi / omega;
493 ROOT::Math::XYZVector position = expectedHelix.getPositionAtArcLength2D(arcLength2D);
494 ROOT::Math::XYZVector momentum = expectedHelix.getMomentumAtArcLength2D(arcLength2D, nominalBz);
495 int chargeSign = expectedHelix.getChargeSign();
497 EXPECT_NEAR(tanLambda, 1 / tan(momentum.Theta()), absError);
498 EXPECT_ANGLE_NEAR(phi0 + chi, momentum.Phi(), absError);
499 EXPECT_NEAR(z0 + tanLambda * arcLength2D, position.Z(), absError);
502 Helix helix(position, momentum, chargeSign, nominalBz);
504 EXPECT_NEAR(expectedHelix.getOmega(), helix.getOmega(), absError);
505 EXPECT_ANGLE_NEAR(expectedHelix.getPhi0(), helix.getPhi0(), absError);
506 EXPECT_NEAR(expectedHelix.getD0(), helix.getD0(), absError);
507 EXPECT_NEAR(expectedHelix.getTanLambda(), helix.getTanLambda(), absError);
508 EXPECT_NEAR(expectedHelix.getZ0(), helix.getZ0(), absError);
602 TEST_F(HelixTest, PassiveMoveExplicit)
604 ROOT::Math::XYZVector center(0.0, 1.0, 0.0);
608 Helix helix = helixFromCenter(center, radius, tanLambda);
610 ASSERT_NEAR(0, helix.getD0(), absError);
611 ASSERT_ANGLE_NEAR(0, helix.getPhi0(), absError);
612 ASSERT_NEAR(-1, helix.getOmega(), absError);
615 Helix expectedHelix(helix);
619 ROOT::Math::XYZVector by(1.0, 1.0, 0.0);
621 float arcLength2D = helix.passiveMoveBy(by);
625 ASSERT_NEAR(M_PI / 2, arcLength2D, absError);
627 ASSERT_NEAR(0, helix.getD0(), absError);
628 ASSERT_ANGLE_NEAR(M_PI / 2, helix.getPhi0(), absError);
629 ASSERT_NEAR(-1, helix.getOmega(), absError);
631 ASSERT_NEAR(3 * M_PI / 2, helix.getZ0(), absError);
632 ASSERT_NEAR(3, helix.getTanLambda(), absError);
635 float arcLength2DBackward = helix.passiveMoveBy(-by);
637 ASSERT_NEAR(arcLength2D, -arcLength2DBackward, absError);
638 ASSERT_ALL_NEAR(expectedHelix, helix, absError);
642 TEST_F(HelixTest, PassiveMove)
647 for (
const float phi0 : phi0s) {
648 for (
const float omega : omegas) {
649 for (
const float d0 : d0s) {
650 for (
const float chi : chis) {
651 for (
const float newD0 : d0s) {
652 Helix helix(d0, phi0, omega, z0, tanLambda);
653 TEST_CONTEXT(
"Failed for " << helix);
657 float expectedArcLength2D = omega == 0 ? chi : -chi / omega;
658 ROOT::Math::XYZVector positionOnHelix = helix.getPositionAtArcLength2D(expectedArcLength2D);
659 ROOT::Math::XYZVector tangentialToHelix = helix.getUnitTangentialAtArcLength2D(expectedArcLength2D);
661 ROOT::Math::XYZVector perpendicularToHelix = tangentialToHelix;
662 perpendicularToHelix = ROOT::Math::VectorUtil::RotateZ(perpendicularToHelix, M_PI / 2.0);
664 perpendicularToHelix *= 1 / perpendicularToHelix.Rho();
666 ROOT::Math::XYZVector displacementFromHelix = -perpendicularToHelix * newD0;
667 ROOT::Math::XYZVector testPosition = positionOnHelix + displacementFromHelix;
669 ROOT::Math::XYZVector expectedPerigee = -displacementFromHelix;
671 TEST_CONTEXT(
"Failed for chi " << chi);
672 TEST_CONTEXT(
"Failed for position on helix " << positionOnHelix);
673 TEST_CONTEXT(
"Failed for tangential to helix " << tangentialToHelix);
674 TEST_CONTEXT(
"Failed for perpendicular to helix " << perpendicularToHelix);
675 TEST_CONTEXT(
"Failed for test position " << testPosition);
677 float arcLength2D = helix.passiveMoveBy(testPosition);
679 ASSERT_NEAR(expectedArcLength2D, arcLength2D, absError);
681 ASSERT_ALL_NEAR(expectedPerigee, helix.getPerigee(), absError);
690 TEST_F(HelixTest, calcPassiveMoveByJacobian_identity)
692 ROOT::Math::XYZVector center(0.0, 1.0, 0.0);
696 Helix helix = helixFromCenter(center, radius, tanLambda);
698 TMatrixD noMoveJacobian = helix.calcPassiveMoveByJacobian(ROOT::Math::XYZVector(0.0, 0.0, 0.0));
700 EXPECT_NEAR(1.0, noMoveJacobian(0, 0), 1e-7);
701 EXPECT_NEAR(0.0, noMoveJacobian(0, 1), 1e-7);
702 EXPECT_NEAR(0.0, noMoveJacobian(0, 2), 1e-7);
704 EXPECT_NEAR(0.0, noMoveJacobian(1, 0), 1e-7);
705 EXPECT_NEAR(1.0, noMoveJacobian(1, 1), 1e-7);
706 EXPECT_NEAR(0.0, noMoveJacobian(1, 2), 1e-7);
708 EXPECT_NEAR(0.0, noMoveJacobian(2, 0), 1e-7);
709 EXPECT_NEAR(0.0, noMoveJacobian(2, 1), 1e-7);
710 EXPECT_NEAR(1.0, noMoveJacobian(2, 2), 1e-7);
713 TEST_F(HelixTest, calcPassiveMoveByJacobian_orthogonalToPhi0)
715 ROOT::Math::XYZVector center(0.0, 1.0, 0.0);
719 Helix helix = helixFromCenter(center, radius, tanLambda);
721 TMatrixD moveByOneJacobian = helix.calcPassiveMoveByJacobian(ROOT::Math::XYZVector(0.0, -1.0, 0.0));
723 EXPECT_NEAR(1.0, moveByOneJacobian(iD0, iD0), 1e-7);
724 EXPECT_NEAR(0.0, moveByOneJacobian(iD0, iPhi0), 1e-7);
725 EXPECT_NEAR(0.0, moveByOneJacobian(iD0, iOmega), 1e-7);
727 EXPECT_NEAR(0.0, moveByOneJacobian(iPhi0, iD0), 1e-7);
728 EXPECT_NEAR(1.0 / 2.0, moveByOneJacobian(iPhi0, iPhi0), 1e-7);
729 EXPECT_NEAR(0.0, moveByOneJacobian(iPhi0, iOmega), 1e-7);
731 EXPECT_NEAR(0.0, moveByOneJacobian(iOmega, iD0), 1e-7);
732 EXPECT_NEAR(0.0, moveByOneJacobian(iOmega, iPhi0), 1e-7);
733 EXPECT_NEAR(1.0, moveByOneJacobian(iOmega, iOmega), 1e-7);
737 TEST_F(HelixTest, calcPassiveMoveByJacobian_parallelToPhi0_compare_opposite_transformation)
739 ROOT::Math::XYZVector center(0.0, 1.0, 0.0);
743 Helix helix = helixFromCenter(center, radius, tanLambda);
745 TMatrixD moveByPlusTwoXJacobian = helix.calcPassiveMoveByJacobian(ROOT::Math::XYZVector(2.0, 0.0, 0.0));
746 TMatrixD moveByMinusTwoXJacobian = helix.calcPassiveMoveByJacobian(ROOT::Math::XYZVector(-2.0, 0.0, 0.0));
748 EXPECT_NEAR(1.0, moveByPlusTwoXJacobian(iOmega, iOmega), 1e-7);
749 EXPECT_NEAR(0.0, moveByPlusTwoXJacobian(iOmega, iPhi0), 1e-7);
750 EXPECT_NEAR(0.0, moveByPlusTwoXJacobian(iOmega, iD0), 1e-7);
752 EXPECT_NEAR(1.0, moveByMinusTwoXJacobian(iOmega, iOmega), 1e-7);
753 EXPECT_NEAR(0.0, moveByMinusTwoXJacobian(iOmega, iPhi0), 1e-7);
754 EXPECT_NEAR(0.0, moveByMinusTwoXJacobian(iOmega, iD0), 1e-7);
757 EXPECT_NEAR(moveByMinusTwoXJacobian(iD0, iOmega), moveByPlusTwoXJacobian(iD0, iOmega), 1e-7);
758 EXPECT_NEAR(moveByMinusTwoXJacobian(iPhi0, iPhi0), moveByPlusTwoXJacobian(iPhi0, iPhi0), 1e-7);
759 EXPECT_NEAR(moveByMinusTwoXJacobian(iD0, iD0), moveByPlusTwoXJacobian(iD0, iD0), 1e-7);
762 EXPECT_NEAR(moveByMinusTwoXJacobian(iD0, iPhi0), -moveByPlusTwoXJacobian(iD0, iPhi0), 1e-7);
763 EXPECT_NEAR(moveByMinusTwoXJacobian(iPhi0, iD0), -moveByPlusTwoXJacobian(iPhi0, iD0), 1e-7);
764 EXPECT_NEAR(moveByMinusTwoXJacobian(iPhi0, iOmega), -moveByPlusTwoXJacobian(iPhi0, iOmega), 1e-7);
767 EXPECT_NEGATIVE(moveByPlusTwoXJacobian(iD0, iPhi0));
768 EXPECT_POSITIVE(moveByPlusTwoXJacobian(iD0, iOmega));
769 EXPECT_POSITIVE(moveByPlusTwoXJacobian(iPhi0, iD0));
770 EXPECT_NEGATIVE(moveByPlusTwoXJacobian(iPhi0, iOmega));
772 EXPECT_NEGATIVE(moveByPlusTwoXJacobian(iD0, iD0) - 1);
773 EXPECT_NEGATIVE(moveByPlusTwoXJacobian(iPhi0, iPhi0) - 1);
776 TEST_F(HelixTest, calcPassiveMoveByJacobian_roundtrip)
778 for (
const auto& by : bys) {
779 ROOT::Math::XYZVector center(0.0, 1.0, 0.0);
783 Helix helix = helixFromCenter(center, radius, tanLambda);
785 TMatrixD jacobian = helix.calcPassiveMoveByJacobian(by);
786 helix.passiveMoveBy(by);
788 TMatrixD reverseJacobian = helix.calcPassiveMoveByJacobian(-by);
790 TMatrixD unitMatrix = reverseJacobian * jacobian;
792 for (
int i = 0; i < 5; ++i) {
793 for (
int j = 0; j < 5; ++j) {
796 EXPECT_NEAR(1, unitMatrix(i, j), 1e-7);
799 EXPECT_NEAR(0, unitMatrix(i, j), 1e-7);
808 TEST_F(HelixTest, calcPassiveMoveByJacobian_parallelToPhi0)
810 ROOT::Math::XYZVector center(1.0, 0.0, 0.0);
814 Helix helix = helixFromCenter(center, radius, tanLambda);
816 TMatrixD moveByTwoYJacobian = helix.calcPassiveMoveByJacobian(ROOT::Math::XYZVector(0.0, 2.0, 0.0));
819 double deltaParallel = 2;
825 double lambda = 1.0 / (5.0 + 3.0 *
sqrt(5.0));
826 double mu =
sqrt(5.0) / 10.0;
829 EXPECT_NEAR(1.0, moveByTwoYJacobian(iOmega, iOmega), 1e-7);
830 EXPECT_NEAR(0.0, moveByTwoYJacobian(iOmega, iPhi0), 1e-7);
831 EXPECT_NEAR(0.0, moveByTwoYJacobian(iOmega, iD0), 1e-7);
833 EXPECT_NEAR(2.0 / 5.0, moveByTwoYJacobian(iPhi0, iOmega), 1e-7);
834 EXPECT_NEAR(1.0 / 5.0, moveByTwoYJacobian(iPhi0, iPhi0), 1e-7);
835 EXPECT_NEAR(-2.0 / 5.0, moveByTwoYJacobian(iPhi0, iD0), 1e-7);
837 EXPECT_NEAR(mu * zeta - A * lambda, moveByTwoYJacobian(iD0, iOmega), 1e-7);
838 EXPECT_NEAR(2.0 * mu * u * deltaParallel, moveByTwoYJacobian(iD0, iPhi0), 1e-7);
839 EXPECT_NEAR(2.0 * mu * nu, moveByTwoYJacobian(iD0, iD0), 1e-7);
844 TEST_F(HelixTest, calcPassiveMoveByJacobian_consistency_of_expansion)
846 ROOT::Math::XYZVector center(0.0, 1.0, 0.0);
850 Helix helix = helixFromCenter(center, radius, tanLambda);
852 for (
const auto& by : bys) {
853 TMatrixD jacobian = helix.calcPassiveMoveByJacobian(by);
854 TMatrixD jacobianWithExpansion = helix.calcPassiveMoveByJacobian(by, 10000);
856 EXPECT_NEAR(1.0, jacobian(iOmega, iOmega), 1e-7);
857 EXPECT_NEAR(0.0, jacobian(iOmega, iPhi0), 1e-7);
858 EXPECT_NEAR(0.0, jacobian(iOmega, iD0), 1e-7);
860 EXPECT_NEAR(1.0, jacobianWithExpansion(iOmega, iOmega), 1e-7);
861 EXPECT_NEAR(0.0, jacobianWithExpansion(iOmega, iPhi0), 1e-7);
862 EXPECT_NEAR(0.0, jacobianWithExpansion(iOmega, iD0), 1e-7);
864 EXPECT_NEAR(jacobianWithExpansion(iD0, iD0), jacobian(iD0, iD0), 1e-7);
865 EXPECT_NEAR(jacobianWithExpansion(iD0, iPhi0), jacobian(iD0, iPhi0), 1e-7);
866 EXPECT_NEAR(jacobianWithExpansion(iD0, iOmega), jacobian(iD0, iOmega), 1e-7);
868 EXPECT_NEAR(jacobianWithExpansion(iPhi0, iD0), jacobian(iPhi0, iD0), 1e-7);
869 EXPECT_NEAR(jacobianWithExpansion(iPhi0, iPhi0), jacobian(iPhi0, iPhi0), 1e-7);
870 EXPECT_NEAR(jacobianWithExpansion(iPhi0, iOmega), jacobian(iPhi0, iOmega), 1e-7);
874 TEST_F(HelixTest, realExample)
877 std::vector<double> helixParams(5);
878 helixParams[0] = 3.82384;
879 helixParams[1] = std::remainder(3.575595, 2 * M_PI);
880 helixParams[2] = 0.00530726;
881 helixParams[3] = -0.000317335;
882 helixParams[4] = 1.34536;
884 ROOT::Math::XYZVector momentum(-0.768755, -0.356297, 1.13994);
885 ROOT::Math::XYZVector position(-1.60794, 3.46933, -0.000317335);
891 const double bZ = 1.5;
894 EXPECT_NEAR(0.0, momentum.X() * position.X() + momentum.Y() * position.Y(), 1e-6);
896 Helix helix(helixParams[0], helixParams[1], helixParams[2], helixParams[3], helixParams[4]);
898 EXPECT_ALL_NEAR(momentum, helix.getMomentum(bZ), 1e-5);
899 EXPECT_ALL_NEAR(position, helix.getPerigee(), 1e-5);
903 TEST_F(HelixTest, omegaForUnitMomentum)
905 ROOT::Math::XYZVector expectedMomentum(1.0, 0.0, 0.0);
906 ROOT::Math::XYZVector expectedPosition(0.0, 1.0, 0.0);
907 const double expectedCharge = 1;
908 const double bZ = 1.5;
910 Helix helix(expectedPosition, expectedMomentum, expectedCharge, bZ);
912 double expectedOmega = 0.0044968868700000003;
913 EXPECT_ALL_NEAR(expectedOmega, helix.getOmega(), 1e-7);
double sqrt(double a)
sqrt for double
double charge(int pdgCode)
Returns electric charge of a particle with given pdg code.
Some utilities to help with writing unit tests.
bool angleNear(double expected, double actual, double tolerance)
Predicate checking that two angular values are close to each other modulus a 2 * PI difference.
bool allNear< Belle2::Helix >(const Belle2::Helix &expected, const Belle2::Helix &actual, double tolerance)
Predicate checking that all five components of the Helix are close by a maximal error of absError.
Abstract base class for different kinds of events.