TrackPropagator.cxx
Go to the documentation of this file.
3 
4 namespace util {
5 
6 
7 
8  //----------------------------------------------------------------------
9  int TrackPropagator::PropagateToCylinder(const float* trackpar, const float* Xpoint,
10  const float rCyl, const float yCyl, const float zCyl, float* retXYZ1, float* retXYZ2,
11  const float Xmax, const float epsilon)
12  {
13  //track fitted parameters (y, z, curvature, phi, lambda)
14  // Don't forget r can be negative! But rCyl can't :)
15  const float y0 = trackpar[0];
16  const float z0 = trackpar[1];
17  const float curv = trackpar[2];
18  const float phi0 = trackpar[3];
19  const float tanl = std::tan(trackpar[4]);
20 
21 
22 
23  // Radius of curvature of track
24  float radius;
25  if (curv != 0) {
26  radius = 1.0 / curv;
27  } else {
28  // Straight-line algorithm not tested. Probably not needed, really.
29  // From Wolfram MathWorld
30  float zL[2]; float yL[2];
31  zL[0] = zCyl -rCyl -1.0; zL[1] = zCyl +rCyl +1.0;
32  for (int i=0; i<2; ++i) yL[i] = y0 +(zL[i] -z0)*std::tan(phi0);
33 
34  float Dx = zL[1] -zL[0]; float Dy = yL[1] -yL[0];
35  float Dr = std::hypot(Dx,Dy); float D = zL[0]*yL[1] -zL[1]*yL[0];
36  float det = (rCyl*Dr)*(rCyl*Dr) - D*D;
37  if (det<0) return 4;
38 
39  float zz1 = (D*Dy +Dx*det) / (Dr*Dr);
40  float zz2 = (D*Dy -Dx*det) / (Dr*Dr);
41  float yy1 = y0 +(zz1 -z0)*std::tan(phi0);
42  float yy2 = y0 +(zz2 -z0)*std::tan(phi0);
43  if ( std::hypot(zz1-z0,yy1-y0) < std::hypot(zz2-z0,yy2-y0) ) {
44  retXYZ1[1] = yy1;
45  retXYZ1[2] = zz1;
46  retXYZ2[1] = yy2;
47  retXYZ2[2] = zz2;
48  } else {
49  retXYZ1[1] = yy2;
50  retXYZ1[2] = zz2;
51  retXYZ2[1] = yy1;
52  retXYZ2[2] = zz1;
53  }
54  retXYZ1[0] = ( retXYZ1[2]-z0 ) / std::cos(phi0);
55  retXYZ2[0] = ( retXYZ2[2]-z0 ) / std::cos(phi0);
56  return 0;
57  }
58 
59 
60  //Coordinate of the center of the circle of radius r
61  float zcc = z0 - radius * std::sin(phi0);
62  float ycc = y0 + radius * std::cos(phi0);
63 
64  // dz and dy are the 'horizontal' and 'vertical' distances between
65  // the circle centers.
66  float dz = zcc - zCyl;
67  float dy = ycc - yCyl;
68 
69  /* Determine the straight-line distance between the centers. */
70  const float d = std::hypot(dy, dz);
71 
72  /* Check for solvability. */
73  if ( d > (rCyl + abs(radius)) ) {
74  /* no solution. circles do not intersect. */
75  return 1;
76  }
77  if (d < std::fabs(rCyl - abs(radius))) {
78  /* no solution. one circle is contained in the other */
79  return 2;
80  }
81  if (d < epsilon) {
82  /* no solution. circles have common centre */
83  return 3;
84  }
85 
86  // Calculate the intersection point between the cylinder and the track
87  float phiStar = (d*d + rCyl*rCyl - radius*radius);
88  phiStar /= 2 * std::max(1.e-20f, rCyl * d);
89  if (phiStar > +1.f) phiStar = +0.9999999f;
90  if (phiStar < -1.f) phiStar = -0.9999999f;
91  phiStar = std::acos(phiStar);
92 
93  float phiCentre(std::atan2(dy, dz));
94 
95  // There are two solutions which can not differ in phi from
96  // phi0 by more than 2pi.
97  float zz1 = zCyl + rCyl * std::cos(phiCentre + phiStar);
98  float yy1 = yCyl + rCyl * std::sin(phiCentre + phiStar);
99  // Add pi/2 or 3pi/2 because of definition of where phi = 0
100  float phi1 = atan2( yy1-ycc, zz1-zcc );
101  phi1 += (curv>=0) ? M_PI/2.0 : 3.0*M_PI/2.0;
102  float zz2 = zCyl + rCyl * std::cos(phiCentre - phiStar);
103  float yy2 = yCyl + rCyl * std::sin(phiCentre - phiStar);
104  float phi2 = atan2( yy2-ycc, zz2-zcc );
105  phi2 += (curv>=0) ? M_PI/2.0 : 3.0*M_PI/2.0;
106 
107  float dphi1 = phi1 -phi0;
108  float dphi2 = phi2 -phi0;
109  int nturns = dphi1/(2.0*M_PI);
110  // bring dphi1 in the range 0-2pi, then into range -pi to +pi
111  if (dphi1 > +(2.0*M_PI)) dphi1 -= (2.0*M_PI)*nturns;
112  if (dphi1 < -(2.0*M_PI)) dphi1 += (2.0*M_PI)*nturns;
113  if (dphi1 > +M_PI) dphi1 -= 2.0*M_PI;
114  if (dphi1 < -M_PI) dphi1 += 2.0*M_PI;
115  // likewise dphi2
116  nturns = dphi2/(2.0*M_PI);
117  if (dphi2 > +(2.0*M_PI)) dphi2 -= (2.0*M_PI)*nturns;
118  if (dphi2 < -(2.0*M_PI)) dphi2 += (2.0*M_PI)*nturns;
119  if (dphi2 > +M_PI) dphi2 -= 2.0*M_PI;
120  if (dphi2 < -M_PI) dphi2 += 2.0*M_PI;
121  if ( fabs(dphi1) < fabs(dphi2) ) {
122  retXYZ1[1] = yy1;
123  retXYZ1[2] = zz1;
124  retXYZ1[0] = Xpoint[0] + radius * tanl * dphi1;
125  retXYZ2[1] = yy2;
126  retXYZ2[2] = zz2;
127  retXYZ2[0] = Xpoint[0] + radius * tanl * dphi2;
128 
129  } else {
130  retXYZ1[1] = yy2;
131  retXYZ1[2] = zz2;
132  retXYZ1[0] = Xpoint[0] + radius * tanl * dphi2;
133  retXYZ2[1] = yy1;
134  retXYZ2[2] = zz1;
135  retXYZ2[0] = Xpoint[0] + radius * tanl * dphi1;
136  }
137 
138  // If Xmax > 0, check if found intersection has x beyond it - i.e.
139  // it might be in the endcap
140  if ( std::fabs(Xmax) > 0 ) {
141  if ( std::fabs(retXYZ1[0]) > std::fabs(Xmax) ) {
142  // std::cout << "5 - x > Xmax, might be in the endcap" << std::endl;
143  return 5;
144  }
145  if ( std::fabs(retXYZ2[0]) > std::fabs(Xmax) ) {
146  return 5;
147  }
148 
149  }
150 
151  return 0;
152  }
153 
154 
155 
156  //----------------------------------------------------------------------
157  int TrackPropagator::PropagateToX(const float* trackpar, const float* Xpoint,
158  const float x, float* retXYZ, const float Rmax)
159  {
160  int retval = 0;
161  float y, z;
162 
163  const float y0 = trackpar[0];
164  const float z0 = trackpar[1];
165  const float phi0 = trackpar[3];
166  const float curv = trackpar[2];
167  float radius = 0;
168  if (curv != 0) radius = 1.0 / curv;
169 
170  float ZCent = trackpar[1] - radius*std::sin(phi0);
171  float YCent = trackpar[0] + radius*std::cos(phi0);
172  float tanl = std::tan(trackpar[4]);
173 
174 
175 
176  if (radius == 0) {
177  // Straight-line case not tested yet
178  float dT = (x -Xpoint[0]) / tanl;
179  y = y0 +dT*std::sin(phi0);
180  z = z0 +dT*std::cos(phi0);
181  retval = 1;
182  } else {
183  float s;
184  if (tanl != 0) {
185  s = 1.0/tanl;
186  } else {
187  s = 1E9;
188  retval = 1;
189  }
190 
191  float phi = (x - Xpoint[0]) * s / radius + phi0;
192  y = YCent - radius * std::cos(phi);
193  z = ZCent + radius * std::sin(phi);
194  }
195 
196  if ( Rmax > 0 ) {
197  if ( std::hypot(z,y) > Rmax ) retval = 2;
198  }
199 
200  retXYZ[0] = x; retXYZ[1] = y; retXYZ[2] = z;
201 
202  return retval;
203  }
204 
205 
206 
207  //----------------------------------------------------------------------
208  int TrackPropagator::DistXYZ(const float* trackpar, const float* Xpoint,
209  const float* xyz, float& retDist) {
210 
211  retDist = 0;
212 
213  // just to make formulas more readable. (xt,yt,zt) = test point.
214  float xt = xyz[0];
215  float yt = xyz[1];
216  float zt = xyz[2];
217 
218  float x0 = Xpoint[0];
219  float y0 = trackpar[0];
220  float z0 = trackpar[1];
221  float curv = trackpar[2];
222  float r = 1.0/curv;
223  float phi0 = trackpar[3];
224 
225  float s = std::tan(trackpar[4]);
226  if (s != 0) {
227  s = 1.0/s;
228  } else {
229  s = 1E9;
230  }
231 
232  float sinphi0 = std::sin(phi0);
233  float cosphi0 = std::cos(phi0);
234  float zc = trackpar[1] - r * sinphi0;
235  float yc = trackpar[0] + r * cosphi0;
236 
237  if (curv == 0) {
238  // distance from a point to a line -- use the norm of the cross product of the
239  // unit vector along the line and the displacement between the test point and
240  // a point on the line
241 
242  float h = std::sqrt(1.0 + s*s);
243  float xhc = s*(yt-y0)*(cosphi0/h) - s*(sinphi0/h)*(zt-z0);
244  float yhc = (zt-z0)/h - s*(xt-x0)*(cosphi0/h);
245  float zhc = s*(xt-x0)*(sinphi0/h) - (yt-y0)/h;
246 
247  retDist = std::sqrt( xhc*xhc + yhc*yhc + zhc*zhc );
248  return 1;
249  }
250 
251  if (s == 0) {
252  // zero slope. The track is another line, this time along the x axis
253  retDist = std::sqrt( TMath::Sq(yt-y0) + TMath::Sq(zt-z0) );
254  return 2;
255  }
256 
257  // general case -- need to compute distance from a point to a helix
258  float span = M_PI;
259  float gold = 1.61803398875;
260 
261  // First guess is phi for this xt; but try also +/- a half turn as
262  // that could easily be closer
263  float phicent = (s*curv)*(xt-x0) +phi0;
264  float d2cent = d2(xt,yt,zt, x0,yc,zc, r,s, phicent, phi0);
265  float philow = phicent -span;
266  float d2low = d2(xt,yt,zt, x0,yc,zc, r,s, philow, phi0);
267  float phihi = phicent +span;
268  float d2hi = d2(xt,yt,zt, x0,yc,zc, r,s, phihi, phi0);
269  if ( d2low<d2cent ) {
270  // In fact, d2low==d2high at this point. Pick one solution,
271  // somewhat arbitrarily; go for the one closest to phi0.
272  if ( std::fabs(philow -phi0) < std::fabs(phihi -phi0) ) {
273  phicent = philow;
274  } else {
275  phicent = phihi;
276  }
277  philow = phicent -span;
278  phihi = phicent +span;
279  }
280 
281 
282  // solve for phi of the closest point using quadratic fit; 18 iters gives
283  // phi to 1mrad accuracy
284  for (size_t iter=0; iter<18; ++iter) {
285  // 2 coefficients of the quadratic; requires (phihi -phicent) == (phicent -philow)
286  float B = (d2hi -d2low) / (2*span);
287  float A = (d2hi +d2low -2*d2cent) / ( 2*span*span );
288  if ( A == 0 ) break; // d2hi, d2low & d2cent all pretty close- just quit
289  phicent += -B / (2*A);
290  span /= gold;
291  philow = phicent -span;
292  phihi = phicent +span;
293  d2cent = d2(xt,yt,zt, x0,yc,zc, r,s, phicent, phi0);
294  d2low = d2(xt,yt,zt, x0,yc,zc, r,s, philow, phi0);
295  d2hi = d2(xt,yt,zt, x0,yc,zc, r,s, phihi, phi0);
296  }
297 
298  float xp = x0 + r*(phicent -phi0)/s;
299  float yp = yc - r*TMath::Cos(phicent);
300  float zp = zc + r*TMath::Sin(phicent);
301  retDist = std::sqrt(TMath::Sq(xt-xp) +TMath::Sq(yt-yp) +TMath::Sq(zt-zp));
302 
303  return 0;
304  }
305 
306 
307 
308  //----------------------------------------------------------------------
309  int TrackPropagator::DirectionX (const float* trackpar, const float* Xpoint,
310  float& xEval, float* retXYZ) {
311 
312  if (trackpar[2]==0) return 1;
313  float r = 1.0/trackpar[2];
314  float s = std::tan(trackpar[4]);
315  float x0 = Xpoint[0];
316 
317  float phi = (xEval -x0)/(r*s);
318  DirectionPhi(trackpar,Xpoint, phi, retXYZ);
319  return 0;
320  }
321 
322 
323 
324  int TrackPropagator::DirectionPhi(const float* trackpar, const float* ,// (unused) Xpoint,
325  float& phiEval, float* retXYZ) {
326 
327  retXYZ[0] = std::tan(trackpar[4]);
328  retXYZ[1] = std::sin(phiEval);
329  retXYZ[2] = std::cos(phiEval);
330  float norm = std::hypot(retXYZ[0],retXYZ[1],retXYZ[2]);
331  for (int i=0; i<3; ++i) retXYZ[i] /= norm;
332 
333  return 0;
334  }
335 
336 
337 
338  //----------------------------------------------------------------------
339  float TrackPropagator::d2(float xt, float yt, float zt,
340  float x0, float yc, float zc, float r, float s, float phi, float phi0)
341  {
342  float dx = (xt -x0) - (r/s)*(phi -phi0);
343  float dy = (yt -yc) + r*TMath::Cos(phi);
344  float dz = (zt -zc) - r*TMath::Sin(phi);
345  return dx*dx + dy*dy + dz*dz;
346  }
347 
348 } //namespace util
span(IterB &&b, IterE &&e, Adaptor &&adaptor) -> span< decltype(adaptor(std::forward< IterB >(b))), decltype(adaptor(std::forward< IterE >(e))) >
Namespace for general, non-LArSoft-specific utilities.
static int DistXYZ(const float *trackpar, const float *Xpoint, const float *xyz, float &retDist)
constexpr auto abs(T v)
Returns the absolute value of the argument.
#define D
Debug message.
Definition: tclscanner.cpp:775
Simple class with a begin and an end.
Definition: span.h:125
std::enable_if_t< std::is_arithmetic_v< T >, T > hypot(T x, T y)
Definition: hypot.h:60
const double e
static int PropagateToX(const float *trackpar, const float *Xpoint, const float x, float *retXYZ, const float Rmax=0.0)
static int PropagateToCylinder(const float *trackpar, const float *Xpoint, const float rCyl, const float yCyl, const float zCyl, float *retXYZ1, float *retXYZ2, const float Xmax=0.0, const float epsilon=2.0e-5)
static int max(int a, int b)
auto norm(Vector const &v)
Return norm of the specified vector.
Interface to propagate a Track to the specific point.
#define M_PI
Definition: includeROOT.h:54
static int DirectionPhi(const float *trackpar, const float *Xpoint, float &phiEval, float *retXYZ)
static int DirectionX(const float *trackpar, const float *Xpoint, float &xEval, float *retXYZ)
#define A
Definition: memgrp.cpp:38
list x
Definition: train.py:276
static float d2(float xt, float yt, float zt, float x0, float yc, float zc, float r, float s, float phi, float phi0)
static QCString * s
Definition: config.cpp:1042