8#include <framework/dataobjects/Helix.h>
10#include <framework/gearbox/Const.h>
12#include <boost/math/special_functions/sign.hpp>
13#include <boost/math/special_functions/sinc.hpp>
14#include <boost/math/tools/precision.hpp>
16#include <Math/VectorUtil.h>
22using namespace HelixParameterIndex;
34 const ROOT::Math::XYZVector& momentum,
35 const short int charge,
45 const double& tanLambda)
50 m_tanLambda(tanLambda)
116 return boost::math::sign(
getOmega());
135 const double dr =
getD0();
136 const double deltaCylindricalR = cylindricalR;
138 return absArcLength2D;
144 double arcLength2D = 0;
150 const double& nX,
const double& nY)
const
153 const double tX = nY;
154 const double tY = -nX;
160 const double d0 =
getD0();
164 const double deltaParallel = byX * cosPhi0 + byY * sinPhi0;
165 const double deltaOrthogonal = byY * cosPhi0 - byX * sinPhi0 + d0;
166 const double deltaCylindricalR = hypot(deltaOrthogonal, deltaParallel);
167 const double deltaCylindricalRSquared = deltaCylindricalR * deltaCylindricalR;
169 const double UOrthogonal = 1 + omega * deltaOrthogonal;
170 const double UParallel = omega * deltaParallel;
173 const double A = 2 * deltaOrthogonal + omega * deltaCylindricalRSquared;
175 const double tParallel = tX * cosPhi0 + tY * sinPhi0;
176 const double tOrthogonal = tY * cosPhi0 - tX * sinPhi0;
177 const double tCylindricalR = (tX * tX + tY * tY);
179 const double c = A / 2;
180 const double b = UParallel * tParallel + UOrthogonal * tOrthogonal;
181 const double a = omega / 2 * tCylindricalR;
183 const double discriminant = ((double)b) * b - 4 * a * c;
184 const double root = sqrt(discriminant);
185 const double bigSum = (b > 0) ? -b - root : -b + root;
187 const double bigOffset = bigSum / 2 / a;
188 const double smallOffset = 2 * c / bigSum;
190 const double distance1 = hypot(byX + bigOffset * tX, byY + bigOffset * tY);
191 const double distance2 = hypot(byX + smallOffset * tX, byY + smallOffset * tY);
193 if (distance1 < distance2) {
225 const double chi = -arcLength2D *
getOmega();
226 const double chiHalf = chi / 2.0;
228 using boost::math::sinc_pi;
230 const double x = arcLength2D * sinc_pi(chi);
231 const double y = arcLength2D * sinc_pi(chiHalf) * sin(chiHalf) -
getD0();
237 ROOT::Math::XYZVector position(x, y, z);
240 position = ROOT::Math::VectorUtil::RotateZ(position,
getPhi0());
251 const double chi = - omega * arcLength2D;
253 const double tx = cos(chi + phi0);
254 const double ty = sin(chi + phi0);
255 const double tz = tanLambda;
257 ROOT::Math::XYZVector tangential(tx, ty, tz);
265 const double invNorm = 1 / norm;
266 unitTangential *= invNorm;
267 return unitTangential;
285 double arcLength2D = 0;
289 double chi = -arcLength2D *
getOmega();
290 double new_phi0 =
m_phi0 + chi;
303 TMatrixD jacobian(5, 5);
312 const double expandBelowChi)
const
316 jacobian.UnitMatrix();
317 assert(jacobian.GetNrows() == jacobian.GetNcols());
318 assert(jacobian.GetNrows() == 5 or jacobian.GetNrows() == 6);
324 const double d0 =
getD0();
329 const double deltaParallel = byX * cosPhi0 + byY * sinPhi0;
330 const double deltaOrthogonal = byY * cosPhi0 - byX * sinPhi0 + d0;
331 const double deltaCylindricalR = hypot(deltaOrthogonal, deltaParallel);
332 const double deltaCylindricalRSquared = deltaCylindricalR * deltaCylindricalR;
335 const double A = 2 * deltaOrthogonal + omega * deltaCylindricalRSquared;
336 const double USquared = 1 + omega * A;
337 const double U = sqrt(USquared);
338 const double UOrthogonal = 1 + omega * deltaOrthogonal;
339 const double UParallel = omega * deltaParallel;
341 const double u = 1 + omega * d0;
352 const double new_d0 = A / (1 + U);
354 jacobian(iD0, iOmega) = (deltaCylindricalR + new_d0) * (deltaCylindricalR - new_d0) / 2 / U;
355 jacobian(iD0, iPhi0) = - u * deltaParallel / U;
356 jacobian(iD0, iD0) = UOrthogonal / U;
361 const double dArcLength2D_dD0 = - UParallel / USquared;
362 const double dArcLength2D_dPhi0 = (omega * deltaCylindricalRSquared + deltaOrthogonal - d0 * UOrthogonal) / USquared;
364 jacobian(iPhi0, iD0) = - dArcLength2D_dD0 * omega;
365 jacobian(iPhi0, iPhi0) = u * UOrthogonal / USquared;
366 jacobian(iPhi0, iOmega) = -deltaParallel / USquared;
375 const double chi = -atan2(UParallel, UOrthogonal);
376 double arcLength2D = 0;
377 double dArcLength2D_dOmega = 0;
379 if (fabs(chi) < std::min(expandBelowChi, M_PI / 2.0)) {
382 double principleArcLength2D = deltaParallel / UOrthogonal;
383 const double dPrincipleArcLength2D_dOmega = - principleArcLength2D * deltaOrthogonal / UOrthogonal;
385 const double x = principleArcLength2D * omega;
389 arcLength2D = principleArcLength2D * f;
390 dArcLength2D_dOmega = (f + x * df_dx) * dPrincipleArcLength2D_dOmega + principleArcLength2D * df_dx * principleArcLength2D;
396 arcLength2D = - chi / omega;
397 dArcLength2D_dOmega = (-arcLength2D - jacobian(iPhi0, iOmega)) / omega;
404 jacobian(iZ0, iD0) = tanLambda * dArcLength2D_dD0;
405 jacobian(iZ0, iPhi0) = tanLambda * dArcLength2D_dPhi0;
406 jacobian(iZ0, iOmega) = tanLambda * dArcLength2D_dOmega;
407 jacobian(iZ0, iZ0) = 1.0;
408 jacobian(iZ0, iTanLambda) = arcLength2D;
410 if (jacobian.GetNrows() == 6) {
412 jacobian(iArcLength2D, iD0) = dArcLength2D_dD0;
413 jacobian(iArcLength2D, iPhi0) = dArcLength2D_dPhi0;
414 jacobian(iArcLength2D, iOmega) = dArcLength2D_dOmega;
415 jacobian(iArcLength2D, iZ0) = 0.0;
416 jacobian(iArcLength2D, iTanLambda) = 0;
417 jacobian(iArcLength2D, iArcLength2D) = 1.0;
423 return std::remainder(phi + M_PI, 2 * M_PI);
434 double x = secantLength *
getOmega() / 2.0;
443 BOOST_MATH_STD_USING;
445 auto const taylor_n_bound = boost::math::tools::forth_root_epsilon<double>();
447 if (abs(x) >= taylor_n_bound) {
460 auto const taylor_0_bound = boost::math::tools::epsilon<double>();
461 if (abs(x) >= taylor_0_bound) {
466 auto const taylor_2_bound = boost::math::tools::root_epsilon<double>();
467 if (abs(x) >= taylor_2_bound) {
469 result += x2 * x2 * (3.0 / 40.0);
482 BOOST_MATH_STD_USING;
484 auto const taylor_n_bound = boost::math::tools::forth_root_epsilon<double>();
486 if (abs(x) >= taylor_n_bound) {
493 auto const taylor_0_bound = boost::math::tools::epsilon<double>();
494 if (abs(x) >= taylor_0_bound) {
499 auto const taylor_2_bound = boost::math::tools::root_epsilon<double>();
500 if (abs(x) >= taylor_2_bound) {
502 result += x2 * x2 * (1.0 / 5.0);
514 BOOST_MATH_STD_USING;
516 auto const taylor_n_bound = boost::math::tools::forth_root_epsilon<double>();
518 const double x2 = x * x;
519 if (abs(x) >= taylor_n_bound) {
520 const double chi = atan(x);
521 return ((1 - chi / x) / x - chi) / (1 + x2);
527 auto const taylor_0_bound = boost::math::tools::epsilon<double>();
528 if (abs(x) >= taylor_0_bound) {
530 result -= 2.0 * x / 3.0;
532 auto const taylor_2_bound = boost::math::tools::root_epsilon<double>();
533 if (abs(x) >= taylor_2_bound) {
535 result += x2 * x * (4.0 / 5.0);
551 const double d0 =
getD0();
553 const double deltaParallel = x * cosPhi0 + y * sinPhi0;
554 const double deltaOrthogonal = y * cosPhi0 - x * sinPhi0 + d0;
555 const double deltaCylindricalR = hypot(deltaOrthogonal, deltaParallel);
556 const double deltaCylindricalRSquared = deltaCylindricalR * deltaCylindricalR;
558 const double A = 2 * deltaOrthogonal + omega * deltaCylindricalRSquared;
559 const double U = sqrt(1 + omega * A);
560 const double UOrthogonal = 1 + omega * deltaOrthogonal;
561 const double UParallel = omega * deltaParallel;
568 const double chi = -atan2(UParallel, UOrthogonal);
570 if (fabs(chi) < M_PI / 8) {
572 double principleArcLength2D = deltaParallel / UOrthogonal;
577 arcLength2D = -chi / omega;
584 double secantLength = sqrt((deltaCylindricalR + dr) * (deltaCylindricalR - dr) / (1 + dr * omega));
589 const ROOT::Math::XYZVector& momentum,
590 const short int charge,
593 assert(abs(charge) <= 1);
601 const double x = position.X();
602 const double y = position.Y();
603 const double z = position.Z();
605 const double px = momentum.X();
606 const double py = momentum.Y();
607 const double pz = momentum.Z();
609 const double ptinv = 1 / hypot(px, py);
610 const double omega = charge * ptinv / alpha;
611 const double tanLambda = ptinv * pz;
612 const double phi0 = atan2(py, px);
635 <<
"d0=" << helix.
getD0() <<
", "
636 <<
"phi0=" << helix.
getPhi0() <<
", "
637 <<
"omega=" << helix.
getOmega() <<
", "
638 <<
"z0=" << helix.
getZ0() <<
", "
static const double speedOfLight
[cm/ns]
This class represents an ideal helix in perigee parameterization.
Double32_t m_tanLambda
Memory for the slope of the track in the z coordinate over the two dimensional arc length (dz/ds)
double getPerigeeX() const
Calculates the x coordinate of the perigee point.
double getSinPhi0() const
Getter for the cosine of the azimuth angle of travel direction at the perigee.
double getMomentumZ(const double bZ) const
Calculates the z momentum of the particle at the perigee point.
Double32_t m_omega
Memory for the curvature of the signed curvature.
double getMomentumY(const double bZ) const
Calculates the y momentum of the particle at the perigee point.
void reverse()
Reverses the direction of travel of the helix in place.
double getCosPhi0() const
Getter for the cosine of the azimuth angle of travel direction at the perigee.
double getArcLength2DAtCylindricalR(const double &cylindricalR) const
Calculates the transverse travel distance at the point the helix first reaches the given cylindrical ...
static double calcASinXDividedByX(const double &x)
Implementation of the function asin(x) / x which handles small x values smoothly.
static double reversePhi(const double &phi)
Reverses an azimuthal angle to the opposite direction.
short getChargeSign() const
Return track charge sign (1, 0 or -1).
double getArcLength2DAtXY(const double &x, const double &y) const
Calculates the two dimensional arc length at which the circle in the xy projection is closest to the ...
Double32_t m_z0
Memory for the z coordinate of the perigee.
static double getAlpha(const double bZ)
Calculates the alpha value for a given magnetic field in Tesla.
double getOmega() const
Getter for omega, which is a signed curvature measure of the track.
ROOT::Math::XYZVector getDirection() const
Getter for unit vector of momentum at the perigee position.
ROOT::Math::XYZVector getTangentialAtArcLength2D(const double &arcLength2D) const
Calculates the tangential vector to the helix curve at the given two dimensional arc length.
ROOT::Math::XYZVector getPositionAtArcLength2D(const double &arcLength2D) const
Calculates the position on the helix at the given two dimensional arc length.
Double32_t m_d0
Memory for the signed distance to the perigee.
ROOT::Math::XYZVector getUnitTangentialAtArcLength2D(const double &arcLength2D) const
Calculates the unit tangential vector to the helix curve at the given two dimensional arc length.
double getPerigeeZ() const
Calculates the z coordinate of the perigee point.
void setCartesian(const ROOT::Math::XYZVector &position, const ROOT::Math::XYZVector &momentum, const short int charge, const double bZ)
Cartesian to Perigee conversion.
double getD0() const
Getter for d0, which is the signed distance to the perigee in the r-phi plane.
ROOT::Math::XYZVector getMomentum(const double bZ) const
Getter for vector of momentum at the perigee position.
void calcArcLength2DAndDrAtXY(const double &x, const double &y, double &arcLength2D, double &dr) const
Helper method to calculate the signed two dimensional arc length and the signed distance to the circl...
double passiveMoveBy(const ROOT::Math::XYZVector &by)
Moves origin of the coordinate system (passive transformation) by the given vector.
double getArcLength2DAtNormalPlane(const double &x, const double &y, const double &nX, const double &nY) const
Calculates the arc length to reach a plane parallel to the z axes.
double getMomentumX(const double bZ) const
Calculates the x momentum of the particle at the perigee point.
double getTanLambda() const
Getter for tan lambda, which is the z over two dimensional arc length slope of the track.
TMatrixD calcPassiveMoveByJacobian(const ROOT::Math::XYZVector &by, const double expandBelowChi=M_PI/8) const
Calculate the 5x5 jacobian matrix for the transport of the helix parameters, when moving the origin o...
double getPerigeeY() const
Calculates the y coordinate of the perigee point.
double calcSecantLengthToArcLength2DFactor(const double &secantLength2D) const
Helper function to calculate the factor between the dimensional secant length and the two dimensional...
Double32_t m_phi0
Memory for the azimuth angle between the transverse momentum and the x axis, which is in [-pi,...
double calcArcLength2DAtDeltaCylindricalRAndDr(const double &deltaCylindricalR, const double &dr) const
Helper method to calculate the two dimensional arc length from the perigee to a point at cylindrical ...
double calcArcLength2DFromSecantLength(const double &secantLength2D) const
Helper function to calculate the two dimensional arc length from the length of a secant.
double getZ0() const
Getter for z0, which is the z coordinate of the perigee.
double getKappa(const double bZ) const
Getter for kappa, which is charge / transverse momentum or equivalently omega * alpha.
static double calcDerivativeOfATanXDividedByX(const double &x)
Implementation of the function d / dx (atan(x) / x) which handles small x values smoothly.
Helix()
Constructor initializing all perigee parameters to zero.
ROOT::Math::XYZVector getMomentumAtArcLength2D(const double &arcLength2D, const double &bz) const
Calculates the momentum vector at the given two dimensional arc length.
ROOT::Math::XYZVector getPerigee() const
Getter for the perigee position.
double getTransverseMomentum(const double bZ) const
Getter for the absolute value of the transverse momentum at the perigee.
double getPhi0() const
Getter for phi0, which is the azimuth angle of the transverse momentum at the perigee.
static double calcATanXDividedByX(const double &x)
Implementation of the function atan(x) / x which handles small x values smoothly.
std::ostream & operator<<(std::ostream &output, const IntervalOfValidity &iov)
Abstract base class for different kinds of events.