CMS 3D CMS Logo

HelixTrajectory.cc
Go to the documentation of this file.
8 #include <cmath>
9 
10 // helix phi definition
11 // ranges from 0 to 2PI
12 // 0 corresponds to the positive x direction
13 // phi increases counterclockwise
14 
16  : Trajectory(particle)
17  // exact: r = gamma*beta*m_0*c / (q*e*B) = p_T / (q * e * B)
18  // momentum in units of GeV/c: r = p_T * 10^9 / (c * q * B)
19  // in cmssw units: r = p_T / (c * 10^-4 * q * B)
20  ,
21  radius_(
22  std::abs(momentum_.Pt() / (fastsim::Constants::speedOfLight * 1e-4 * particle.charge() * magneticFieldZ))),
23  phi_(std::atan(momentum_.Py() / momentum_.Px()) +
24  (momentum_.Px() * particle.charge() < 0 ? 3. * M_PI / 2. : M_PI / 2.))
25  // maybe consider (for -pi/2<x<pi/2)
26  // cos(atan(x)) = 1 / sqrt(x^2+1)
27  // -> cos(atan(x) + pi/2) = - x / sqrt(x^2+1)
28  // -> cos(atan(x) +3*pi/2) = + x / sqrt(x^2+1)
29  // sin(atan(x)) = x / sqrt(x^2+1)
30  // -> sin(atan(x) + pi/2) = + 1 / sqrt(x^2+1)
31  // -> sin(atan(x) +3*pi/2) = - 1 / sqrt(x^2+1)
32  ,
33  centerX_(position_.X() -
34  radius_ * (momentum_.Py() / momentum_.Px()) /
35  std::sqrt((momentum_.Py() / momentum_.Px()) * (momentum_.Py() / momentum_.Px()) + 1) *
36  (momentum_.Px() * particle.charge() < 0 ? 1. : -1.)),
37  centerY_(position_.Y() -
38  radius_ * 1 / std::sqrt((momentum_.Py() / momentum_.Px()) * (momentum_.Py() / momentum_.Px()) + 1) *
39  (momentum_.Px() * particle.charge() < 0 ? -1. : 1.))
40  //, centerX_(position_.X() - radius_*std::cos(phi_))
41  //, centerY_(position_.Y() - radius_*std::sin(phi_))
42  ,
43  centerR_(std::sqrt(centerX_ * centerX_ + centerY_ * centerY_)),
44  minR_(std::abs(centerR_ - radius_)),
45  maxR_(centerR_ + radius_)
46  // omega = q * e * B / (gamma * m) = q * e *B / (E / c^2) = q * e * B * c^2 / E
47  // omega: negative for negative q -> seems to be what we want.
48  // energy in units of GeV: omega = q * B * c^2 / (E * 10^9)
49  // in cmssw units: omega[1/ns] = q * B * c^2 * 10^-4 / E
50  ,
51  phiSpeed_(-particle.charge() * magneticFieldZ * fastsim::Constants::speedOfLight *
52  fastsim::Constants::speedOfLight * 1e-4 / momentum_.E()) {
53  ;
54 }
55 
57  return (minR_ < layer.getRadius() && maxR_ > layer.getRadius());
58 }
59 
61  if (!crosses(layer))
62  return -1;
63 
64  // solve the following equation for sin(phi)
65  // (x^2 + y^2 = R_L^2) (1) the layer
66  // x = x_c + R_H*cos(phi) (2) the helix in the xy plane
67  // y = y_c + R_H*sin(phi) (3) the helix in the xy plane
68  // with
69  // R_L: the radius of the layer
70  // x_c,y_c the center of the helix in xy plane
71  // R_H, the radius of the helix
72  // phi, the phase of the helix
73  //
74  // substitute (2) and (3) in (1)
75  // =>
76  // x_c^2 + 2*x_c*R_H*cos(phi) + R_H^2*cos^2(phi)
77  // + y_c^2 + 2*y_c*R_H*sin(phi) + R_H^2*sin^2(phi)
78  // = R_L^2
79  // =>
80  // (x_c^2 + y_c^2 + R_H^2 - R_L^2) + (2*y_c*R_H)*sin(phi) = -(2*x_c*R_H)*cos(phi)
81  //
82  // rewrite
83  // E + F *sin(phi) = G *cos(phi)
84  // =>
85  // E^2 + 2*E*F*sin(phi) + F^2*sin^2(phi) = G^2*(1-sin^2(phi))
86  // rearrange
87  // sin^2(phi)*(F^2 + G^2) + sin(phi)*(2*E*F) + (E^2 - G^2) = 0
88  //
89  // rewrite
90  // sin^2(phi)* a + sin(phi)* b + c = 0
91  // => sin(phi) = (-b +/- sqrt(b^2 - 4*ac)) / (2*a)
92  // with
93  // a = F^2 + G^2
94  // b = 2*E*F
95  // c = E^2 - G^2
96 
97  double E = centerX_ * centerX_ + centerY_ * centerY_ + radius_ * radius_ - layer.getRadius() * layer.getRadius();
98  double F = 2 * centerY_ * radius_;
99  double G = 2 * centerX_ * radius_;
100 
101  double a = F * F + G * G;
102  double b = 2 * E * F;
103  double c = E * E - G * G;
104 
105  double delta = b * b - 4 * a * c;
106 
107  // case of no solution
108  if (delta < 0) {
109  // Should not be reached: Full Propagation does always have a solution "if(crosses(layer)) == -1"
110  // Even if particle is outside all layers -> can turn around in magnetic field
111  return -1;
112  }
113 
114  // Uses a numerically more stable procedure:
115  // https://people.csail.mit.edu/bkph/articles/Quadratics.pdf
116  double sqrtDelta = sqrt(delta);
117  double phi1 = 0, phi2 = 0;
118  if (b < 0) {
119  phi1 = std::asin((2. * c) / (-b + sqrtDelta));
120  phi2 = std::asin((-b + sqrtDelta) / (2. * a));
121  } else {
122  phi1 = std::asin((-b - sqrtDelta) / (2. * a));
123  phi2 = std::asin((2. * c) / (-b - sqrtDelta));
124  }
125 
126  // asin is ambiguous, make sure to have the right solution
127  if (std::abs(layer.getRadius() - getRadParticle(phi1)) > 1.0e-2) {
128  phi1 = -phi1 + M_PI;
129  }
130  if (std::abs(layer.getRadius() - getRadParticle(phi2)) > 1.0e-2) {
131  phi2 = -phi2 + M_PI;
132  }
133 
134  // another ambiguity
135  if (phi1 < 0) {
136  phi1 += 2. * M_PI;
137  }
138  if (phi2 < 0) {
139  phi2 += 2. * M_PI;
140  }
141 
142  // find the corresponding times when the intersection occurs
143  // make sure they are positive
144  double t1 = (phi1 - phi_) / phiSpeed_;
145  while (t1 < 0) {
146  t1 += 2 * M_PI / std::abs(phiSpeed_);
147  }
148  double t2 = (phi2 - phi_) / phiSpeed_;
149  while (t2 < 0) {
150  t2 += 2 * M_PI / std::abs(phiSpeed_);
151  }
152 
153  // Check if propagation successful (numerical reasons): both solutions (phi1, phi2) have to be on the layer (same radius)
154  // Can happen due to numerical instabilities of geometrical function (if momentum is almost parallel to x/y axis)
155  // Get crossingTimeC from StraightTrajectory as good approximation
156  if (std::abs(layer.getRadius() - getRadParticle(phi1)) > 1.0e-2 ||
157  std::abs(layer.getRadius() - getRadParticle(phi2)) > 1.0e-2) {
158  StraightTrajectory traj(*this);
159  return traj.nextCrossingTimeC(layer, onLayer);
160  }
161 
162  // if the particle is already on the layer, we need to make sure the 2nd solution is picked.
163  // happens if particle turns around in the magnetic field instead of hitting the next layer
164  if (onLayer) {
165  bool particleMovesInwards = momentum_.X() * position_.X() + momentum_.Y() * position_.Y() < 0;
166 
167  double posX1 = centerX_ + radius_ * std::cos(phi1);
168  double posY1 = centerY_ + radius_ * std::sin(phi1);
169  double momX1 = momentum_.X() * std::cos(phi1 - phi_) - momentum_.Y() * std::sin(phi1 - phi_);
170  double momY1 = momentum_.X() * std::sin(phi1 - phi_) + momentum_.Y() * std::cos(phi1 - phi_);
171  bool particleMovesInwards1 = momX1 * posX1 + momY1 * posY1 < 0;
172 
173  double posX2 = centerX_ + radius_ * std::cos(phi2);
174  double posY2 = centerY_ + radius_ * std::sin(phi2);
175  double momX2 = momentum_.X() * std::cos(phi2 - phi_) - momentum_.Y() * std::sin(phi2 - phi_);
176  double momY2 = momentum_.X() * std::sin(phi2 - phi_) + momentum_.Y() * std::cos(phi2 - phi_);
177  bool particleMovesInwards2 = momX2 * posX2 + momY2 * posY2 < 0;
178 
179  if (particleMovesInwards1 != particleMovesInwards) {
181  } else if (particleMovesInwards2 != particleMovesInwards) {
183  }
184  // try to catch numerical issues again..
185  else {
186  return -1;
187  }
188  }
189 
191 }
192 
193 void fastsim::HelixTrajectory::move(double deltaTimeC) {
194  double deltaT = deltaTimeC / fastsim::Constants::speedOfLight;
195  double deltaPhi = phiSpeed_ * deltaT;
196  position_.SetXYZT(centerX_ + radius_ * std::cos(phi_ + deltaPhi),
197  centerY_ + radius_ * std::sin(phi_ + deltaPhi),
198  position_.Z() + momentum_.Z() / momentum_.E() * deltaTimeC,
199  position_.T() + deltaT);
200  // Rotation defined by
201  // x' = x cos θ - y sin θ
202  // y' = x sin θ + y cos θ
203  momentum_.SetXYZT(momentum_.X() * std::cos(deltaPhi) - momentum_.Y() * std::sin(deltaPhi),
204  momentum_.X() * std::sin(deltaPhi) + momentum_.Y() * std::cos(deltaPhi),
205  momentum_.Z(),
206  momentum_.E());
207 }
208 
210  return sqrt((centerX_ + radius_ * std::cos(phi)) * (centerX_ + radius_ * std::cos(phi)) +
211  (centerY_ + radius_ * std::sin(phi)) * (centerY_ + radius_ * std::sin(phi)));
212 }
const double minR_
The minimal distance of the helix from the center of the tracker.
const double phi_
Ranges from 0 to 2PI: 0 corresponds to the positive X direction, phi increases counterclockwise.
Sin< T >::type sin(const T &t)
Definition: Sin.h:22
const double radius_
The radius of the helix.
#define X(str)
Definition: MuonsGrabber.cc:38
Implementation of a barrel detector layer (cylindrical).
static double constexpr speedOfLight
Speed of light [cm / ns].
Definition: Constants.h:12
const double centerY_
Y-coordinate of the center of the helix.
double getRadParticle(double phi) const
Return distance of particle from center of the detector if it was at given angle phi of the helix...
math::XYZTLorentzVector position_
position of the particle that was used to create trajectory
Definition: Trajectory.h:91
T sqrt(T t)
Definition: SSEVec.h:19
Mathematical representation of a straight trajectory.
Cos< T >::type cos(const T &t)
Definition: Cos.h:22
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
const double maxR_
The maximum distance of the helix from the center of the tracker.
T min(T a, T b)
Definition: MathUtil.h:58
const double phiSpeed_
The angular speed of the particle on the helix trajectory.
#define M_PI
bool crosses(const BarrelSimplifiedGeometry &layer) const override
Check if an intersection of the trajectory with a barrel layer exists.
double nextCrossingTimeC(const BarrelSimplifiedGeometry &layer, bool onLayer=false) const override
Return delta time (t*c) of the next intersection of trajectory and barrel layer.
Definition the generic trajectory of a particle (base class for helix/straight trajectories).
Definition: Trajectory.h:26
const double centerX_
X-coordinate of the center of the helix.
void move(double deltaTimeC) override
Move the particle along the helix trajectory for a given time.
double b
Definition: hdecay.h:118
HelixTrajectory(const Particle &particle, double magneticFieldZ)
Constructor.
double a
Definition: hdecay.h:119
double nextCrossingTimeC(const BarrelSimplifiedGeometry &layer, bool onLayer=false) const override
Return delta time (t*c) of the next intersection of trajectory and barrel layer.
const double getRadius() const
Return radius of the barrel layer.
Definition of a generic FastSim Particle which can be propagated through the detector (formerly Parti...
Definition: Particle.h:16
math::XYZTLorentzVector momentum_
momentum of the particle that was used to create trajectory
Definition: Trajectory.h:92
static uInt32 F(BLOWFISH_CTX *ctx, uInt32 x)
Definition: blowfish.cc:163