8 #include <framework/dataobjects/Helix.h>
10 #include <Math/VectorUtil.h>
11 #include <Math/Vector2D.h>
15 #include <framework/utilities/TestHelpers.h>
17 #include <gtest/gtest.h>
21 using namespace HelixParameterIndex;
24 std::ostream&
operator<<(::std::ostream& output,
const TVector3& tVector3)
28 << tVector3.X() <<
", "
29 << tVector3.Y() <<
", "
30 << tVector3.Z() <<
")";
44 bool d0Near = fabs(expected.getD0() - actual.getD0()) < tolerance;
45 bool phi0Near =
angleNear(expected.getPhi0(), actual.getPhi0(), tolerance);
46 bool omegaNear = fabs(expected.getOmega() - actual.getOmega()) < tolerance;
47 bool z0Near = fabs(expected.getZ0() - actual.getZ0()) < tolerance;
48 bool tanLambdaNear = fabs(expected.getTanLambda() - actual.getTanLambda()) < tolerance;
50 return d0Near and phi0Near and omegaNear and z0Near and tanLambdaNear;
55 Belle2::Helix helixFromCenter(
const ROOT::Math::XYZVector& center,
const float& radius,
const float& tanLambda)
57 double omega = 1 / radius;
58 double phi0 = center.Phi() + copysign(M_PI / 2.0, radius);
59 double d0 = copysign(center.Rho(), radius) - radius;
60 double z0 = center.Z();
66 vector<float> linspace(
const float& start,
const float& end,
const int n)
68 std::vector<float> result(n);
72 for (
int i = 1; i < n - 1; ++i) {
73 float start_weight = (float)(n - 1 - i) / (n - 1);
74 float end_weight = 1 - start_weight;
75 result[i] = start * start_weight + end * end_weight;
82 class HelixTest :
public ::testing::Test {
86 double absError = 1e-6;
87 double nominalBz = 1.5;
89 std::vector<float> omegas { -1, 0, 1};
91 std::vector<float> phi0s = linspace(-M_PI, M_PI, 11);
92 std::vector<float> d0s { -0.5, -0.2, 0, 0.2, 0.5};
94 std::vector<float> chis = linspace(-5 * M_PI / 6, 5 * M_PI / 6, 11);
96 std::vector<ROOT::Math::XYZVector> bys = {
97 ROOT::Math::XYZVector(-2.0, 0.5, 0.0),
98 ROOT::Math::XYZVector(-1.0, 0.5, 0.0),
99 ROOT::Math::XYZVector(0.0, 0.5, 0.0),
100 ROOT::Math::XYZVector(1.0, 0.5, 0.0),
101 ROOT::Math::XYZVector(2.0, 0.5, 0.0),
103 ROOT::Math::XYZVector(-2.0, 0.0, 0.0),
104 ROOT::Math::XYZVector(-1.0, 0.0, 0.0),
105 ROOT::Math::XYZVector(0.0, 0.0, 0.0),
106 ROOT::Math::XYZVector(1.0, 0.0, 0.0),
107 ROOT::Math::XYZVector(2.0, 0.0, 0.0),
109 ROOT::Math::XYZVector(-2.0, -1.0, 0.0),
110 ROOT::Math::XYZVector(-1.0, -1.0, 0.0),
111 ROOT::Math::XYZVector(0.0, -1.0, 0.0),
112 ROOT::Math::XYZVector(1.0, -1.0, 0.0),
113 ROOT::Math::XYZVector(2.0, -1.0, 0.0),
119 TEST_F(HelixTest, Getters)
122 unsigned int nCases = 1;
123 double bField = nominalBz;
125 for (
unsigned int i = 0; i < nCases; ++i) {
127 short int charge = generator.Uniform(-1, 1) > 0 ? 1 : -1;
130 ROOT::Math::XYVector d(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
131 ROOT::Math::XYVector pt(generator.Uniform(-1, 1), generator.Uniform(-1, 1));
132 d.SetCoordinates(d.X(), -d.X() * pt.X() / pt.Y());
135 ROOT::Math::XYZVector position(d.X(), d.Y(), generator.Uniform(-1, 1));
136 ROOT::Math::XYZVector momentum(pt.X(), pt.Y(), generator.Uniform(-1, 1));
139 Helix helix(position, momentum, charge, bField);
142 EXPECT_ALL_NEAR(position, helix.getPerigee(), absError);
143 EXPECT_ALL_NEAR(momentum, helix.getMomentum(bField), absError);
146 EXPECT_NEAR(momentum.Rho(), helix.getTransverseMomentum(bField), absError);
149 EXPECT_NEAR(charge / momentum.Rho(), helix.getKappa(bField), absError);
153 EXPECT_NEAR(position.Rho(), fabs(helix.getD0()), absError);
156 EXPECT_SAME_SIGN(position.Cross(momentum).Z(), helix.getD0());
159 EXPECT_NEAR(momentum.Phi(), helix.getPhi0(), absError);
162 EXPECT_NEAR(position.Z(), helix.getZ0(), absError);
165 EXPECT_NEAR(1 /
tan(momentum.Theta()), helix.getTanLambda(), absError);
168 EXPECT_NEAR(1 /
tan(momentum.Theta()), helix.getCotTheta(), absError);
171 EXPECT_EQ(charge, helix.getChargeSign());
176 TEST_F(HelixTest, SignOfD0)
180 const ROOT::Math::XYZVector position(1, 0, 0);
181 const ROOT::Math::XYZVector momentum(0, 1, 0);
182 const ROOT::Math::XYZVector oppositeMomentum(0, -1, 0);
184 const float bField = nominalBz;
186 Helix helix(position, momentum, charge, bField);
187 EXPECT_NEAR(1, helix.getD0(), absError);
190 Helix helix2(position, momentum, -charge, bField);
191 EXPECT_NEAR(1, helix2.getD0(), absError);
194 Helix oppositeMomentumHelix(position, oppositeMomentum, charge, bField);
195 EXPECT_NEAR(-1, oppositeMomentumHelix.getD0(), absError);
197 Helix oppositeMomentumHelix2(position, oppositeMomentum, -charge, bField);
198 EXPECT_NEAR(-1, oppositeMomentumHelix2.getD0(), absError);
210 ROOT::Math::XYZVector center(0.0, -2.0, 0.0);
215 Helix helix = helixFromCenter(center, radius, tanLambda);
217 ROOT::Math::XYZVector actualCenter = helix.getPerigee() * ((1 / helix.getOmega() + helix.getD0()) / helix.getD0());
218 EXPECT_NEAR(center.X(), actualCenter.X(), absError);
219 EXPECT_NEAR(center.Y(), actualCenter.Y(), absError);
222 TEST_F(HelixTest, Explicit)
230 ROOT::Math::XYZVector center(0.0, -2.0, 0.0);
235 Helix helix = helixFromCenter(center, radius, tanLambda);
236 EXPECT_NEAR(-1, helix.getD0(), absError);
237 EXPECT_ANGLE_NEAR(-M_PI, helix.getPhi0(), absError);
238 EXPECT_NEAR(-1, helix.getOmega(), absError);
243 float arcLength2D = 0;
244 ROOT::Math::XYZVector position = helix.getPositionAtArcLength2D(arcLength2D);
245 ROOT::Math::XYZVector tangential = helix.getUnitTangentialAtArcLength2D(arcLength2D);
247 EXPECT_ALL_NEAR(ROOT::Math::XYZVector(0.0, -1.0, 0.0), position, absError);
248 EXPECT_ANGLE_NEAR(-M_PI, tangential.Phi(), absError);
252 float arcLength2D = M_PI / 2;
253 ROOT::Math::XYZVector position = helix.getPositionAtArcLength2D(arcLength2D);
254 ROOT::Math::XYZVector tangential = helix.getUnitTangentialAtArcLength2D(arcLength2D);
255 EXPECT_ALL_NEAR(ROOT::Math::XYZVector(-1.0, -2.0, 0.0), position, absError);
256 EXPECT_ANGLE_NEAR(-M_PI / 2, tangential.Phi(), absError);
260 float arcLength2D = M_PI;
261 ROOT::Math::XYZVector position = helix.getPositionAtArcLength2D(arcLength2D);
262 ROOT::Math::XYZVector tangential = helix.getUnitTangentialAtArcLength2D(arcLength2D);
263 EXPECT_ALL_NEAR(ROOT::Math::XYZVector(0.0, -3.0, 0.0), position, absError);
264 EXPECT_ANGLE_NEAR(0, tangential.Phi(), absError);
268 float arcLength2D = 3 * M_PI / 2 ;
269 ROOT::Math::XYZVector position = helix.getPositionAtArcLength2D(arcLength2D);
270 ROOT::Math::XYZVector tangential = helix.getUnitTangentialAtArcLength2D(arcLength2D);
271 EXPECT_ALL_NEAR(ROOT::Math::XYZVector(1.0, -2.0, 0.0), position, absError);
272 EXPECT_ANGLE_NEAR(M_PI / 2, tangential.Phi(), absError);
276 TEST_F(HelixTest, Tangential)
281 for (
const float d0 : d0s) {
282 for (
const float phi0 : phi0s) {
283 for (
const float omega : omegas) {
285 Helix helix(d0, phi0, omega, z0, tanLambda);
286 TEST_CONTEXT(
"Failed for " << helix);
288 ROOT::Math::XYZVector tangentialAtPerigee = helix.getUnitTangentialAtArcLength2D(0.0);
290 EXPECT_ANGLE_NEAR(phi0, tangentialAtPerigee.Phi(), absError);
291 EXPECT_FLOAT_EQ(1.0, tangentialAtPerigee.R());
292 EXPECT_FLOAT_EQ(tanLambda, 1 /
tan(tangentialAtPerigee.Theta()));
294 for (
const float chi : chis) {
298 float arcLength2D = chi;
301 ROOT::Math::XYZVector tangential = helix.getUnitTangentialAtArcLength2D(arcLength2D);
302 EXPECT_ALL_NEAR(tangentialAtPerigee, tangential, absError);
305 float arcLength2D = -chi / omega;
306 ROOT::Math::XYZVector tangential = helix.getUnitTangentialAtArcLength2D(arcLength2D);
308 float actualChi = ROOT::Math::VectorUtil::DeltaPhi(tangentialAtPerigee, tangential);
309 EXPECT_ANGLE_NEAR(chi, actualChi, absError);
310 EXPECT_FLOAT_EQ(tangentialAtPerigee.Theta(), tangential.Theta());
311 EXPECT_FLOAT_EQ(1, tangential.R());
322 TEST_F(HelixTest, MomentumExtrapolation)
325 float tanLambda = -2;
327 for (
const float d0 : d0s) {
328 for (
const float phi0 : phi0s) {
329 for (
const float omega : omegas) {
332 Helix helix(d0, phi0, omega, z0, tanLambda);
333 ROOT::Math::XYZVector momentumAtPerigee = helix.getMomentum(nominalBz);
334 for (
const float chi : chis) {
336 float arcLength2D = -chi / omega;
337 ROOT::Math::XYZVector extrapolatedMomentum = helix.getMomentumAtArcLength2D(arcLength2D, nominalBz);
339 float actualChi = ROOT::Math::VectorUtil::DeltaPhi(momentumAtPerigee, extrapolatedMomentum);
340 EXPECT_ANGLE_NEAR(chi, actualChi, absError);
341 EXPECT_FLOAT_EQ(momentumAtPerigee.Theta(), extrapolatedMomentum.Theta());
342 EXPECT_FLOAT_EQ(momentumAtPerigee.R(), extrapolatedMomentum.R());
352 TEST_F(HelixTest, Extrapolation)
359 for (
const float d0 : d0s) {
360 for (
const float phi0 : phi0s) {
361 for (
const float omega : omegas) {
363 Helix helix(d0, phi0, omega, z0, tanLambda);
364 ROOT::Math::XYZVector perigee = helix.getPerigee();
366 ROOT::Math::XYZVector tangentialAtPerigee = helix.getUnitTangentialAtArcLength2D(0.0);
367 TEST_CONTEXT(
"Failed for " << helix);
371 for (
const float chi : chis) {
372 TEST_CONTEXT(
"Failed for chi = " << chi);
376 float expectedArcLength2D = omega != 0 ? -chi / omega : chi;
377 ROOT::Math::XYZVector pointOnHelix = helix.getPositionAtArcLength2D(expectedArcLength2D);
379 float cylindricalR = pointOnHelix.Rho();
380 float arcLength2D = helix.getArcLength2DAtCylindricalR(cylindricalR);
383 EXPECT_NEAR(fabs(expectedArcLength2D), arcLength2D, absError);
386 ROOT::Math::XYZVector secantVector = pointOnHelix - perigee;
388 if (expectedArcLength2D == 0) {
389 EXPECT_NEAR(0, secantVector.R(), absError);
391 ROOT::Math::XYVector secantVectorXY(secantVector.X(), secantVector.Y());
393 ROOT::Math::XYVector tangentialXY(tangentialAtPerigee.X(), tangentialAtPerigee.Y());
394 float coalignment = secantVectorXY.Dot(tangentialXY);
396 bool extrapolationIsForward = coalignment > 0;
397 bool expectedIsForward = expectedArcLength2D > 0;
398 EXPECT_EQ(expectedIsForward, extrapolationIsForward);
407 TEST_F(HelixTest, ExtrapolationToNormalPlane)
410 ROOT::Math::XYZVector center(0.0, 2.0, 0.0);
414 Helix helix = helixFromCenter(center, radius, tanLambda);
421 double arcLength2D = helix.getArcLength2DAtNormalPlane(x, y, nx, ny);
422 EXPECT_NEAR(-M_PI / 2, arcLength2D, absError);
426 ROOT::Math::XYZVector center(0.0, 2.0, 0.0);
430 Helix helix = helixFromCenter(center, radius, tanLambda);
437 double arcLength2D = helix.getArcLength2DAtNormalPlane(x, y, nx, ny);
438 EXPECT_NEAR(M_PI / 2, arcLength2D, absError);
442 ROOT::Math::XYZVector center(0.0, 2.0, 0.0);
446 Helix helix = helixFromCenter(center, radius, tanLambda);
453 double arcLength2D = helix.getArcLength2DAtNormalPlane(x, y, nx, ny);
454 EXPECT_NEAR(M_PI / 2, arcLength2D, absError);
458 ROOT::Math::XYZVector center(0.0, 2.0, 0.0);
462 Helix helix = helixFromCenter(center, radius, tanLambda);
469 double arcLength2D = helix.getArcLength2DAtNormalPlane(x, y, nx, ny);
470 EXPECT_NEAR(-M_PI / 2, arcLength2D, absError);
477 TEST_F(HelixTest, PerigeeExtrapolateRoundTrip)
480 float tanLambda = -2;
482 for (
const float d0 : d0s) {
483 for (
const float phi0 : phi0s) {
484 for (
const float omega : omegas) {
488 Helix expectedHelix(d0, phi0, omega, z0, tanLambda);
490 for (
const float chi : chis) {
491 float arcLength2D = -chi / omega;
492 ROOT::Math::XYZVector position = expectedHelix.getPositionAtArcLength2D(arcLength2D);
493 ROOT::Math::XYZVector momentum = expectedHelix.getMomentumAtArcLength2D(arcLength2D, nominalBz);
494 int chargeSign = expectedHelix.getChargeSign();
496 EXPECT_NEAR(tanLambda, 1 /
tan(momentum.Theta()), absError);
497 EXPECT_ANGLE_NEAR(phi0 + chi, momentum.Phi(), absError);
498 EXPECT_NEAR(z0 + tanLambda * arcLength2D, position.Z(), absError);
501 Helix helix(position, momentum, chargeSign, nominalBz);
503 EXPECT_NEAR(expectedHelix.getOmega(), helix.getOmega(), absError);
504 EXPECT_ANGLE_NEAR(expectedHelix.getPhi0(), helix.getPhi0(), absError);
505 EXPECT_NEAR(expectedHelix.getD0(), helix.getD0(), absError);
506 EXPECT_NEAR(expectedHelix.getTanLambda(), helix.getTanLambda(), absError);
507 EXPECT_NEAR(expectedHelix.getZ0(), helix.getZ0(), absError);
601 TEST_F(HelixTest, PassiveMoveExplicit)
603 ROOT::Math::XYZVector center(0.0, 1.0, 0.0);
607 Helix helix = helixFromCenter(center, radius, tanLambda);
609 ASSERT_NEAR(0, helix.getD0(), absError);
610 ASSERT_ANGLE_NEAR(0, helix.getPhi0(), absError);
611 ASSERT_NEAR(-1, helix.getOmega(), absError);
614 Helix expectedHelix(helix);
618 ROOT::Math::XYZVector by(1.0, 1.0, 0.0);
620 float arcLength2D = helix.passiveMoveBy(by);
624 ASSERT_NEAR(M_PI / 2, arcLength2D, absError);
626 ASSERT_NEAR(0, helix.getD0(), absError);
627 ASSERT_ANGLE_NEAR(M_PI / 2, helix.getPhi0(), absError);
628 ASSERT_NEAR(-1, helix.getOmega(), absError);
630 ASSERT_NEAR(3 * M_PI / 2, helix.getZ0(), absError);
631 ASSERT_NEAR(3, helix.getTanLambda(), absError);
634 float arcLength2DBackward = helix.passiveMoveBy(-by);
636 ASSERT_NEAR(arcLength2D, -arcLength2DBackward, absError);
637 ASSERT_ALL_NEAR(expectedHelix, helix, absError);
641 TEST_F(HelixTest, PassiveMove)
646 for (
const float phi0 : phi0s) {
647 for (
const float omega : omegas) {
648 for (
const float d0 : d0s) {
649 for (
const float chi : chis) {
650 for (
const float newD0 : d0s) {
651 Helix helix(d0, phi0, omega, z0, tanLambda);
652 TEST_CONTEXT(
"Failed for " << helix);
656 float expectedArcLength2D = omega == 0 ? chi : -chi / omega;
657 ROOT::Math::XYZVector positionOnHelix = helix.getPositionAtArcLength2D(expectedArcLength2D);
658 ROOT::Math::XYZVector tangentialToHelix = helix.getUnitTangentialAtArcLength2D(expectedArcLength2D);
660 ROOT::Math::XYZVector perpendicularToHelix = tangentialToHelix;
661 perpendicularToHelix = ROOT::Math::VectorUtil::RotateZ(perpendicularToHelix, M_PI / 2.0);
663 perpendicularToHelix *= 1 / perpendicularToHelix.Rho();
665 ROOT::Math::XYZVector displacementFromHelix = -perpendicularToHelix * newD0;
666 ROOT::Math::XYZVector testPosition = positionOnHelix + displacementFromHelix;
668 ROOT::Math::XYZVector expectedPerigee = -displacementFromHelix;
670 TEST_CONTEXT(
"Failed for chi " << chi);
671 TEST_CONTEXT(
"Failed for position on helix " << positionOnHelix);
672 TEST_CONTEXT(
"Failed for tangential to helix " << tangentialToHelix);
673 TEST_CONTEXT(
"Failed for perpendicular to helix " << perpendicularToHelix);
674 TEST_CONTEXT(
"Failed for test position " << testPosition);
676 float arcLength2D = helix.passiveMoveBy(testPosition);
678 ASSERT_NEAR(expectedArcLength2D, arcLength2D, absError);
680 ASSERT_ALL_NEAR(expectedPerigee, helix.getPerigee(), absError);
689 TEST_F(HelixTest, calcPassiveMoveByJacobian_identity)
691 ROOT::Math::XYZVector center(0.0, 1.0, 0.0);
695 Helix helix = helixFromCenter(center, radius, tanLambda);
697 TMatrixD noMoveJacobian = helix.calcPassiveMoveByJacobian(ROOT::Math::XYZVector(0.0, 0.0, 0.0));
699 EXPECT_NEAR(1.0, noMoveJacobian(0, 0), 1e-7);
700 EXPECT_NEAR(0.0, noMoveJacobian(0, 1), 1e-7);
701 EXPECT_NEAR(0.0, noMoveJacobian(0, 2), 1e-7);
703 EXPECT_NEAR(0.0, noMoveJacobian(1, 0), 1e-7);
704 EXPECT_NEAR(1.0, noMoveJacobian(1, 1), 1e-7);
705 EXPECT_NEAR(0.0, noMoveJacobian(1, 2), 1e-7);
707 EXPECT_NEAR(0.0, noMoveJacobian(2, 0), 1e-7);
708 EXPECT_NEAR(0.0, noMoveJacobian(2, 1), 1e-7);
709 EXPECT_NEAR(1.0, noMoveJacobian(2, 2), 1e-7);
712 TEST_F(HelixTest, calcPassiveMoveByJacobian_orthogonalToPhi0)
714 ROOT::Math::XYZVector center(0.0, 1.0, 0.0);
718 Helix helix = helixFromCenter(center, radius, tanLambda);
720 TMatrixD moveByOneJacobian = helix.calcPassiveMoveByJacobian(ROOT::Math::XYZVector(0.0, -1.0, 0.0));
722 EXPECT_NEAR(1.0, moveByOneJacobian(iD0, iD0), 1e-7);
723 EXPECT_NEAR(0.0, moveByOneJacobian(iD0, iPhi0), 1e-7);
724 EXPECT_NEAR(0.0, moveByOneJacobian(iD0, iOmega), 1e-7);
726 EXPECT_NEAR(0.0, moveByOneJacobian(iPhi0, iD0), 1e-7);
727 EXPECT_NEAR(1.0 / 2.0, moveByOneJacobian(iPhi0, iPhi0), 1e-7);
728 EXPECT_NEAR(0.0, moveByOneJacobian(iPhi0, iOmega), 1e-7);
730 EXPECT_NEAR(0.0, moveByOneJacobian(iOmega, iD0), 1e-7);
731 EXPECT_NEAR(0.0, moveByOneJacobian(iOmega, iPhi0), 1e-7);
732 EXPECT_NEAR(1.0, moveByOneJacobian(iOmega, iOmega), 1e-7);
736 TEST_F(HelixTest, calcPassiveMoveByJacobian_parallelToPhi0_compare_opposite_transformation)
738 ROOT::Math::XYZVector center(0.0, 1.0, 0.0);
742 Helix helix = helixFromCenter(center, radius, tanLambda);
744 TMatrixD moveByPlusTwoXJacobian = helix.calcPassiveMoveByJacobian(ROOT::Math::XYZVector(2.0, 0.0, 0.0));
745 TMatrixD moveByMinusTwoXJacobian = helix.calcPassiveMoveByJacobian(ROOT::Math::XYZVector(-2.0, 0.0, 0.0));
747 EXPECT_NEAR(1.0, moveByPlusTwoXJacobian(iOmega, iOmega), 1e-7);
748 EXPECT_NEAR(0.0, moveByPlusTwoXJacobian(iOmega, iPhi0), 1e-7);
749 EXPECT_NEAR(0.0, moveByPlusTwoXJacobian(iOmega, iD0), 1e-7);
751 EXPECT_NEAR(1.0, moveByMinusTwoXJacobian(iOmega, iOmega), 1e-7);
752 EXPECT_NEAR(0.0, moveByMinusTwoXJacobian(iOmega, iPhi0), 1e-7);
753 EXPECT_NEAR(0.0, moveByMinusTwoXJacobian(iOmega, iD0), 1e-7);
756 EXPECT_NEAR(moveByMinusTwoXJacobian(iD0, iOmega), moveByPlusTwoXJacobian(iD0, iOmega), 1e-7);
757 EXPECT_NEAR(moveByMinusTwoXJacobian(iPhi0, iPhi0), moveByPlusTwoXJacobian(iPhi0, iPhi0), 1e-7);
758 EXPECT_NEAR(moveByMinusTwoXJacobian(iD0, iD0), moveByPlusTwoXJacobian(iD0, iD0), 1e-7);
761 EXPECT_NEAR(moveByMinusTwoXJacobian(iD0, iPhi0), -moveByPlusTwoXJacobian(iD0, iPhi0), 1e-7);
762 EXPECT_NEAR(moveByMinusTwoXJacobian(iPhi0, iD0), -moveByPlusTwoXJacobian(iPhi0, iD0), 1e-7);
763 EXPECT_NEAR(moveByMinusTwoXJacobian(iPhi0, iOmega), -moveByPlusTwoXJacobian(iPhi0, iOmega), 1e-7);
766 EXPECT_NEGATIVE(moveByPlusTwoXJacobian(iD0, iPhi0));
767 EXPECT_POSITIVE(moveByPlusTwoXJacobian(iD0, iOmega));
768 EXPECT_POSITIVE(moveByPlusTwoXJacobian(iPhi0, iD0));
769 EXPECT_NEGATIVE(moveByPlusTwoXJacobian(iPhi0, iOmega));
771 EXPECT_NEGATIVE(moveByPlusTwoXJacobian(iD0, iD0) - 1);
772 EXPECT_NEGATIVE(moveByPlusTwoXJacobian(iPhi0, iPhi0) - 1);
775 TEST_F(HelixTest, calcPassiveMoveByJacobian_roundtrip)
777 for (
const auto& by : bys) {
778 ROOT::Math::XYZVector center(0.0, 1.0, 0.0);
782 Helix helix = helixFromCenter(center, radius, tanLambda);
784 TMatrixD jacobian = helix.calcPassiveMoveByJacobian(by);
785 helix.passiveMoveBy(by);
787 TMatrixD reverseJacobian = helix.calcPassiveMoveByJacobian(-by);
789 TMatrixD unitMatrix = reverseJacobian * jacobian;
791 for (
int i = 0; i < 5; ++i) {
792 for (
int j = 0; j < 5; ++j) {
795 EXPECT_NEAR(1, unitMatrix(i, j), 1e-7);
798 EXPECT_NEAR(0, unitMatrix(i, j), 1e-7);
807 TEST_F(HelixTest, calcPassiveMoveByJacobian_parallelToPhi0)
809 ROOT::Math::XYZVector center(1.0, 0.0, 0.0);
813 Helix helix = helixFromCenter(center, radius, tanLambda);
815 TMatrixD moveByTwoYJacobian = helix.calcPassiveMoveByJacobian(ROOT::Math::XYZVector(0.0, 2.0, 0.0));
818 double deltaParallel = 2;
824 double lambda = 1.0 / (5.0 + 3.0 *
sqrt(5.0));
825 double mu =
sqrt(5.0) / 10.0;
828 EXPECT_NEAR(1.0, moveByTwoYJacobian(iOmega, iOmega), 1e-7);
829 EXPECT_NEAR(0.0, moveByTwoYJacobian(iOmega, iPhi0), 1e-7);
830 EXPECT_NEAR(0.0, moveByTwoYJacobian(iOmega, iD0), 1e-7);
832 EXPECT_NEAR(2.0 / 5.0, moveByTwoYJacobian(iPhi0, iOmega), 1e-7);
833 EXPECT_NEAR(1.0 / 5.0, moveByTwoYJacobian(iPhi0, iPhi0), 1e-7);
834 EXPECT_NEAR(-2.0 / 5.0, moveByTwoYJacobian(iPhi0, iD0), 1e-7);
836 EXPECT_NEAR(mu * zeta - A * lambda, moveByTwoYJacobian(iD0, iOmega), 1e-7);
837 EXPECT_NEAR(2.0 * mu * u * deltaParallel, moveByTwoYJacobian(iD0, iPhi0), 1e-7);
838 EXPECT_NEAR(2.0 * mu * nu, moveByTwoYJacobian(iD0, iD0), 1e-7);
843 TEST_F(HelixTest, calcPassiveMoveByJacobian_consistency_of_expansion)
845 ROOT::Math::XYZVector center(0.0, 1.0, 0.0);
849 Helix helix = helixFromCenter(center, radius, tanLambda);
851 for (
const auto& by : bys) {
852 TMatrixD jacobian = helix.calcPassiveMoveByJacobian(by);
853 TMatrixD jacobianWithExpansion = helix.calcPassiveMoveByJacobian(by, 10000);
855 EXPECT_NEAR(1.0, jacobian(iOmega, iOmega), 1e-7);
856 EXPECT_NEAR(0.0, jacobian(iOmega, iPhi0), 1e-7);
857 EXPECT_NEAR(0.0, jacobian(iOmega, iD0), 1e-7);
859 EXPECT_NEAR(1.0, jacobianWithExpansion(iOmega, iOmega), 1e-7);
860 EXPECT_NEAR(0.0, jacobianWithExpansion(iOmega, iPhi0), 1e-7);
861 EXPECT_NEAR(0.0, jacobianWithExpansion(iOmega, iD0), 1e-7);
863 EXPECT_NEAR(jacobianWithExpansion(iD0, iD0), jacobian(iD0, iD0), 1e-7);
864 EXPECT_NEAR(jacobianWithExpansion(iD0, iPhi0), jacobian(iD0, iPhi0), 1e-7);
865 EXPECT_NEAR(jacobianWithExpansion(iD0, iOmega), jacobian(iD0, iOmega), 1e-7);
867 EXPECT_NEAR(jacobianWithExpansion(iPhi0, iD0), jacobian(iPhi0, iD0), 1e-7);
868 EXPECT_NEAR(jacobianWithExpansion(iPhi0, iPhi0), jacobian(iPhi0, iPhi0), 1e-7);
869 EXPECT_NEAR(jacobianWithExpansion(iPhi0, iOmega), jacobian(iPhi0, iOmega), 1e-7);
873 TEST_F(HelixTest, realExample)
876 std::vector<double> helixParams(5);
877 helixParams[0] = 3.82384;
878 helixParams[1] = std::remainder(3.575595, 2 * M_PI);
879 helixParams[2] = 0.00530726;
880 helixParams[3] = -0.000317335;
881 helixParams[4] = 1.34536;
883 ROOT::Math::XYZVector momentum(-0.768755, -0.356297, 1.13994);
884 ROOT::Math::XYZVector position(-1.60794, 3.46933, -0.000317335);
890 const double bZ = 1.5;
893 EXPECT_NEAR(0.0, momentum.X() * position.X() + momentum.Y() * position.Y(), 1e-6);
895 Helix helix(helixParams[0], helixParams[1], helixParams[2], helixParams[3], helixParams[4]);
897 EXPECT_ALL_NEAR(momentum, helix.getMomentum(bZ), 1e-5);
898 EXPECT_ALL_NEAR(position, helix.getPerigee(), 1e-5);
902 TEST_F(HelixTest, omegaForUnitMomentum)
904 ROOT::Math::XYZVector expectedMomentum(1.0, 0.0, 0.0);
905 ROOT::Math::XYZVector expectedPosition(0.0, 1.0, 0.0);
906 const double expectedCharge = 1;
907 const double bZ = 1.5;
909 Helix helix(expectedPosition, expectedMomentum, expectedCharge, bZ);
911 double expectedOmega = 0.0044968868700000003;
912 EXPECT_ALL_NEAR(expectedOmega, helix.getOmega(), 1e-7);
TEST_F(GlobalLabelTest, LargeNumberOfTimeDependentParameters)
Test large number of time-dep params for registration and retrieval.
std::ostream & operator<<(std::ostream &output, const Helix &helix)
Output operator for debugging and the generation of unittest error messages.
double sqrt(double a)
sqrt for double
double tan(double a)
tan 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.
Abstract base class for different kinds of events.