Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DMagneticFieldStepper.cc
Go to the documentation of this file.
1 
2 #include <iostream>
3 #include <iomanip>
4 #include <cmath>
5 using namespace std;
6 
9 #include <DVector2.h>
10 
11 #define qBr2p 0.003 // conversion for converting q*B*r to GeV/c
12 
13 #define MAX_SWIM_DIST 2000.0 // Maximum distance to swim a track in cm
14 
15 //-----------------------
16 // DMagneticFieldStepper
17 //-----------------------
19 {
20  this->bfield = bfield;
21  this->q = q;
22  start_pos = pos = DVector3(0.0,0.0,0.0);
23  start_mom = mom = DVector3(0.0,0.0,1.0);
24  last_stepsize = stepsize = 0.5; // in cm
25  CalcDirs();
26 }
27 
28 //-----------------------
29 // DMagneticFieldStepper
30 //-----------------------
32 {
33  this->bfield = bfield;
34  this->q = q;
35  start_pos = pos = *x;
36  start_mom = mom = *p;
37  last_stepsize = stepsize = 0.5; // in cm
38  CalcDirs();
39 }
40 
41 //-----------------------
42 // ~DMagneticFieldStepper
43 //-----------------------
45 {
46 
47 }
48 
49 //-----------------------
50 // SetStartingParams
51 //-----------------------
52 jerror_t DMagneticFieldStepper::SetStartingParams(double q, const DVector3 *x, const DVector3 *p)
53 {
54  this->q = q;
55  start_pos = pos = *x;
56  start_mom = mom = *p;
57  this->last_stepsize = this->stepsize;
58  CalcDirs();
59 
60  return NOERROR;
61 }
62 
63 //-----------------------
64 // SetMagneticFieldMap
65 //-----------------------
67 {
68  this->bfield = bfield;
69 
70  return NOERROR;
71 }
72 
73 //-----------------------
74 // SetStepSize
75 //-----------------------
77 {
78  this->stepsize = step;
79  this->last_stepsize = step;
80 
81  return NOERROR;
82 }
83 
84 //-----------------------
85 // CalcDirs
86 //-----------------------
88 {
89  /// Calculate the directions of the "natural coordinates"
90  /// (aka reference trajectory coordinate system) in the
91  /// lab frame using the current momentum and magnetic field
92  /// at the current position. The results are left in the
93  /// private member fields, copies of which may be obtained
94  /// by a subsequent call to the GetDirs(...) and GetRo()
95  /// methods.
96 
97  // Get B-field
98  double Bx,By,Bz;
99  if(Bvals){
100  // If B-field was already calculated for us then use it
101  Bx = Bvals[0];
102  By = Bvals[1];
103  Bz = Bvals[2];
104  }else{
105  // Have to find field ourselves
106  bfield->GetField(pos.x(), pos.y(), pos.z(), Bx, By, Bz);
107  }
108  B.SetXYZ(Bx, By, Bz);
109 
110  // If the B-field is zero, then default to lab system
111  double Bmag = B.Mag();
112  if(Bmag==0.0){
113  xdir.SetXYZ(1.0,0.0,0.0);
114  ydir.SetXYZ(0.0,1.0,0.0);
115  zdir.SetXYZ(0.0,0.0,1.0);
116  cos_theta = 1.0;
117  sin_theta = 0.0;
118  Rp = Ro = 1.0E20; // This shouldn't really be used ever
119  return;
120  }
121 
122  double momMag = mom.Mag();
123  double one_over_BMagXmomMag = 1./(Bmag * momMag);
124 
125  // cross product of p and B (natural x-direction)
126  xdir = mom.Cross(B);
127  sin_theta = xdir.Mag()*one_over_BMagXmomMag;
128  if(xdir.Mag2()<1.0E-6)xdir = mom.Orthogonal();
129  if(xdir.Mag2()!=0.0)xdir.SetMag(1.0);
130 
131  // cross product of B and pxB (natural y-direction)
132  ydir = B.Cross(xdir);
133  if(ydir.Mag2()!=0.0)ydir.SetMag(1.0);
134 
135  // B-field is natural z-direction
136  zdir = B;
137  if(zdir.Mag2()!=0.0)zdir.SetMag(1.0);
138 
139 
140  // cosine of angle between p and B
141  // double theta = B.Angle(mom);
142  //cos_theta = cos(theta);
143  cos_theta = B.Dot( mom )*one_over_BMagXmomMag;
144  // sin_theta = sin(theta);
145 
146  // Calculate Rp and Ro for this momentum and position
147  Rp = momMag /(q*Bmag*qBr2p); // qBr2p converts to GeV/c/cm so Rp will be in cm
148  Ro = Rp*sin_theta;
149 }
150 
151 #if 1
152 //extern "C" {
153 int grkuta_(double *CHARGE, double *STEP, double *VECT, double *VOUT,const DMagneticFieldMap *bfield);
154 //}
155 
156 
157 // Alternate stepper that does not use the 4th order Runge-Kutta method but a simpler
158 // calculation that depends on a single itermediate step. Assumes that the magnetic field
159 // is constant over the full step. Only looks up the magnetic field once.
160 double DMagneticFieldStepper::FastStep(double stepsize){
161  if(stepsize==0.0)stepsize = this->stepsize;
162 
163  // Current position and momentum
164  double x=pos.x(),y=pos.y(),z=pos.z();
165  double px=mom.x(),py=mom.y(),pz=mom.z();
166  double p=mom.Mag();
167 
168  // B-field at this position
169  bfield->GetField(pos,B);
170 
171  // Compute convenience terms involving Bx, By, Bz
172  double k_q=0.002998*q;
173  double ds_over_p=stepsize/p;
174  double factor=k_q*(0.25*ds_over_p);
175  double Bx=B.x(),By=B.y(),Bz=B.z();
176  double Ax=factor*Bx,Ay=factor*By,Az=factor*Bz;
177  double Ax2=Ax*Ax,Ay2=Ay*Ay,Az2=Az*Az;
178  double AxAy=Ax*Ay,AxAz=Ax*Az,AyAz=Ay*Az;
179  double one_plus_Ax2=1.+Ax2;
180  double scale=ds_over_p/(one_plus_Ax2+Ay2+Az2);
181 
182  // Compute position increments
183  double dx=scale*(px*one_plus_Ax2+py*(AxAy+Az)+pz*(AxAz-Ay));
184  double dy=scale*(px*(AxAy-Az)+py*(1.+Ay2)+pz*(AyAz+Ax));
185  double dz=scale*(px*(AxAz+Ay)+py*(AyAz-Ax)+pz*(1.+Az2));
186 
187  pos.SetXYZ(x+dx,y+dy,z+dz);
188  mom.SetXYZ(px+k_q*(Bz*dy-By*dz),py+k_q*(Bx*dz-Bz*dx),
189  pz+k_q*(By*dx-Bx*dy));
190 
191  return stepsize;
192 }
193 
194 //-----------------------
195 // Step
196 //-----------------------
197 double DMagneticFieldStepper::Step(DVector3 *newpos, DVector3 *B,double stepsize)
198 {
199  double VECT[7], VOUT[7+3]; // modified grkuta so VOUT has B-field returned as additional 3 elements of array
200  VECT[0] = pos.x();
201  VECT[1] = pos.y();
202  VECT[2] = pos.z();
203  VECT[6] = mom.Mag();
204  VECT[3] = mom.x()/VECT[6];
205  VECT[4] = mom.y()/VECT[6];
206  VECT[5] = mom.z()/VECT[6];
207  if(stepsize==0.0)stepsize = this->stepsize;
208  double &STEP = stepsize;
209  double &CHARGE = q;
210 
211  // Call GEANT3 Runge Kutta step routine (see grkuta.c)
212  grkuta_(&CHARGE, &STEP, VECT, VOUT, bfield);
213 
214  pos.SetXYZ(VOUT[0], VOUT[1], VOUT[2]);
215  mom.SetXYZ(VOUT[3], VOUT[4], VOUT[5]);
216  mom.SetMag(VOUT[6]);
217 
218  CalcDirs(&VOUT[7]); // Argument is pointer to array of doubles holding Bx, By, Bz
219  //CalcDirs();
220 
221  if (B){
222  B->SetXYZ(VOUT[7],VOUT[8],VOUT[9]);
223  }
224  if(newpos)*newpos = pos;
225 
226  return STEP;
227 }
228 
229 #else
230 
231 //-----------------------
232 // Step
233 //-----------------------
234 double DMagneticFieldStepper::Step(DVector3 *newpos, double stepsize)
235 {
236  /// Advance the track one step. Copy the new position into the
237  /// DVector3 pointer (if given). Returns distance along path
238  /// traversed in step.
239 
240  // The idea here is to work in the coordinate system whose
241  // axes point in directions defined in the following way:
242  // z-axis is along direction of B-field
243  // x-axis is in direction perpendicular to both B and p (particle momentum)
244  // y-axis is then just cross product of z and x axes.
245  //
246  // These coordinates are referred to as the natural coordinates below.
247  // The step is calculated based on moving along a perfect helix a distance
248  // of "stepsize". This means that the new position will actually be
249  // closer than stepsize to the current position (unless the magnetic field
250  // is zero in which case they are equal).
251  //
252  // The values of the helix needed to project the step are
253  // calculated for the current momentum and position in CalcDirs()
254  // above. They should already be corect for the step we are
255  // about to take. We call CalcDirs() after updating the position
256  // and momentum in order to prepare for the next step.
257 
258  // If we weren't passed a step size, then calculate it using
259  // info stored in the member data
260  if(stepsize==0.0){
261  // We always try growing the step size a little
262  stepsize = 1.25*this->last_stepsize;
263 
264  // Don't grow past the set stepsize
265  if(stepsize>this->stepsize)stepsize=this->stepsize;
266  }
267 
268  // If the magnetic field is zero or the charge is zero, then our job is easy
269  if(B.Mag2()==0.0 || q==0.0){
270  DVector3 pstep = mom;
271  pstep.SetMag(stepsize);
272  pos += pstep;
273  if(newpos)*newpos = pos;
274  CalcDirs();
275 
276  return stepsize;
277  }
278 
279  // Note that cos_theta, sin_theta, Rp, Ro, xdir, ydir, and zdir
280  // should already be valid for the starting point of this step.
281  // They are set via a call to CalcDirs()
282 
283  // delta_z is step size in z direction
284  DVector3 delta_z = zdir*stepsize*cos_theta;
285 
286  // delta_phi is angle of rotation in natural x/y plane
287  double delta_phi = stepsize/Rp;
288 
289  // delta_x is magnitude of step in natural x direction
290  DVector3 delta_x = Ro*(1.0-cos(delta_phi))*xdir;
291 
292  // delta_y is magnitude of step in natural y direction
293  DVector3 delta_y = Ro*sin(delta_phi)*ydir;
294 
295  // Calculate new position
296  DVector3 mypos = pos + delta_x + delta_y + delta_z;
297 
298  // Adjust the step size if needed.
299  // Check that the field hasn't changed too much here. If it has,
300  // reduce the step size and try again.
301  // We actually check three conditions:
302  // 1.) That the step size is not already too small
303  // 2.) that the radius of curvature is still not so big
304  // that it is worth reducing the step size
305  // 3.) that the difference of the field between the old
306  // and new points is small relative to the field size
307  if(stepsize>0.1){
308  if(fabs(stepsize/Ro) > 1.0E-4){
309  double Bx,By,Bz;
310  bfield->GetField(mypos.x(), mypos.y(), mypos.z(), Bx, By, Bz);
311  DVector3 Bnew(Bx, By, Bz);
312  DVector3 Bdiff = B-Bnew;
313  double f = Bdiff.Mag()/B.Mag();
314  if(f > 1.0E-4){
315  return Step(newpos, stepsize/2.0);
316  }
317  }
318  }
319 
320  // Step to new position
321  pos = mypos;
322 
323  // Update momentum by rotating it by delta_phi about B
324  mom.Rotate(-delta_phi, B);
325 
326  // Energy loss for 1.0GeV pions in Air is roughly 2.4keV/cm
327  //double m = 0.13957;
328  //double p = mom.Mag();
329  //double E = sqrt(m*m + p*p) - 0.0000024*stepsize;
330  //mom.SetMag(sqrt(E*E-m*m));
331 
332  // Calculate directions of natural coordinates at the new position
333  CalcDirs();
334 
335  // return new position
336  if(newpos)*newpos = pos;
337 
338  // Record this step size for (possible) use on the next iteration
339  last_stepsize = stepsize;
340 
341  return stepsize;
342 }
343 #endif
344 
345 //-----------------------
346 // GetDirs
347 //-----------------------
349 {
350  xdir = this->xdir;
351  ydir = this->ydir;
352  zdir = this->zdir;
353 }
354 
355 //-----------------------
356 // SwimToPlane
357 //-----------------------
358 bool DMagneticFieldStepper::SwimToPlane(DVector3 &mypos, DVector3 &mymom, const DVector3 &origin, const DVector3 &norm, double *pathlen)
359 {
360  /// Swim the particle from the given position/momentum to
361  /// the plane defined by origin and norm. "origin" should define a point
362  /// somewhere in the plane and norm a vector normal to the plane.
363  /// The charge of the particle is set by the constructor or last
364  /// call to SetStartingParameters(...).
365  ///
366  /// If a non-NULL value is passed for <i>pathlen</i> then the pathlength
367  /// of the track from the given starting position to the intersection point
368  /// is given.
369  ///
370  /// <b>THE FOLLOWING FEATURE IS CURRENTLY DISABLED!</b>
371  /// Note that a check is made that the particle is initially going
372  /// toward the plane. If the particle appears to be going away
373  /// from the plane, then the momentum is temporarily flipped as
374  /// well as the charge so that the particle is swum backwards.
375  ///
376  /// Particles will only be swum a distance of
377  /// MAX_SWIM_DIST (currently hardwired to 20 meters) along their
378  /// trajectory before returning boolean true indicating failure
379  /// to intersect the plane.
380  ///
381  /// On success, a value of false is returned and the values in
382  /// pos and mom will be updated with the position and momentum at
383  /// the point of intersection with the plane.
384 
385  // The method here is to step until we cross the plane.
386  // This is indicated by the value k flipping its sign where
387  // k is defined by:
388  //
389  // k = (pos-origin).norm
390  //
391  // where pos, origin, and norm are all vectors and the "."
392  // indicates a dot product.
393  //
394  // Once the plane is crossed, we know the intersection point is
395  // less than one step away from the current step.
396 
397  // First, we determine whether we are going toward or away from
398  // the plane for the given position/momentum. Note that we could
399  // make the wrong choice here for certain geometries where the
400  // curvature of the swimming changes direction enough.
401 
402 //_DBG_<<"This routine is not debugged!!!"<<endl;
403  double b = norm.Dot(mymom)*norm.Dot(pos-origin);
404  bool momentum_and_charge_flipped = false;
405  if(b<0.0){
406  momentum_and_charge_flipped = true;
407  //mom = -mom;
408  //q = -q;
409  }
410 
411  // Set the starting parameters and start stepping!
412  SetStartingParams(q, &mypos, &mymom);
413  double k, start_k = norm.Dot(mypos-origin);
414  double s = 0.0;
415  DVector3 last_pos;
416  do{
417  last_pos = mypos;
418 
419  s += Step(&mypos);
420  if(s>MAX_SWIM_DIST){
421  if(momentum_and_charge_flipped){
422  //mom = -mom;
423  //q = -q;
424  }
425  return true;
426  }
427  k = norm.Dot(mypos-origin);
428  }while(k/start_k > 0.0);
429 
430  // OK, now pos should define a point
431  // close enough to the plane that we can approximate the position
432  // along the helix as a function of phi. phi is defined as the
433  // phi angle about the center of the helix such that phi=0 points
434  // to the current step position itself. This is similar to,
435  // but not as complicated as, how the distance from the trajectory
436  // to a wire is calculated in DReferenceTrajectory::DistToRT.
437  // See the comments there for more details.
438  double dz_dphi = Ro*mom.Dot(zdir)/mom.Dot(ydir);
439 
440  // It turns out there are cases than can cause dz_dphi to be
441  // a large or non-finite number. Check for this here. If that
442  // is the case, switch to using a linear approximation between
443  // the current and last positions
444  bool use_straight_track_projection = false; // used if our quadratic approx. fails
445  if(isfinite(dz_dphi) && fabs(dz_dphi)<1.0E8){
446 
447  DVector3 pos_diff = mypos - origin;
448  double A = xdir.Dot(norm);
449  double B = ydir.Dot(norm);
450  double C = zdir.Dot(norm);
451  double D = pos_diff.Dot(norm);
452 
453  double alpha = -A*Ro/2.0;
454 
455  // If alpha is zero here (which it is if "norm" happens to be perpendicular
456  // to "xdir") then we will need to fall back to a linear projection
457  if(alpha!=0.0 && isfinite(alpha)){
458 
459  double beta = B*Ro + C*dz_dphi;
460 
461  // now we solve the quadratic equation for phi. It's not obvious
462  // a priori which root will be correct so we calculate both and
463  // choose the one closer to phi=0
464  double d = sqrt(beta*beta - 4.0*alpha*D);
465  double phi1 = (-beta + d)/(2.0*alpha);
466  double phi2 = (-beta - d)/(2.0*alpha);
467  double phi = fabs(phi1)<fabs(phi2) ? phi1:phi2;
468 
469  // Calculate position in plane
470  mypos += -Ro*phi*phi/2.0*xdir + Ro*phi*ydir + dz_dphi*phi*zdir;
471 
472  // Calculate momentum in plane
473  mom.Rotate(phi, zdir);
474 
475  //double delta = sqrt(pow(Ro*phi*phi/2.0, 2.0) + pow(Ro*phi, 2.0) + pow(dz_dphi*phi, 2.0));
476  double temp1=Ro*phi;
477  double temp2=0.5*temp1*phi;
478  double temp3=dz_dphi*phi;
479  double delta=sqrt(temp1*temp1+temp2*temp2+temp3*temp3);
480 
481  s += (phi<0 ? -delta:+delta);
482  }else{
483  use_straight_track_projection = true;
484  }
485  }else{
486  use_straight_track_projection = true;
487  }
488 
489  if(use_straight_track_projection){
490  // Treat as straight track.
491  double num = norm.Dot(origin - last_pos);
492  double den = norm.Dot( mypos - last_pos);
493  double alpha = num/den;
494 
495  DVector3 delta = mypos - last_pos;
496  mypos = last_pos + alpha*delta;
497  s -= (1.0-alpha)*delta.Mag();
498  }
499 
500  // Copy path length into caller's variable if supplied
501  if(pathlen)*pathlen = s ;
502 
503  // If we had to flip the particle in order to hit the plane, flip it back
504  if(momentum_and_charge_flipped){
505  //mom = -mom;
506  //q = -q;
507  }
508  // Return the momentum at the current position
509  mymom=mom;
510 
511  return false;
512 }
513 
514 //-----------------------
515 // DistToPlane
516 //-----------------------
517 bool DMagneticFieldStepper::DistToPlane(DVector3 &pos, const DVector3 &origin, const DVector3 &norm)
518 {
519 
520  return false;
521 }
522 
523 //-----------------------
524 // SwimToPOCAtoBeamLine
525 //-----------------------
527 {
528  /// Routine to find the position-of-closest approach of a trajectory
529  /// to the beam line. Upon entry, q, pos, and mom contain a point
530  /// on a track pointing away from the beamline. (Beamline is assumed
531  /// to be along z at x=y=0). At return, the pos and mom vectors will
532  /// contain the position and momentum at the POCA. Upon success, a boolean
533  /// "false" is returned. If the routine fails, then a boolean "true"
534  /// is returned and the values of pos and mom are left to what they
535  /// were upon entry.
536 
537 
538  // Set the starting parameters and start stepping!
539  DVector3 mymom_loc = -mymom;
540  DVector3 mypos_loc = mypos;
541  SetStartingParams(q, &mypos_loc, &mymom_loc);
542 
543  // Swim until either we start going further away from the beamline
544  // or exit the active volume. (The latter is just a safety net as
545  // we should always be going further from the beamline if we are
546  // exiting the active volume!)
547  DVector3 last_pos;
548  double old_doca2=1001.0, doca2=1000.0;
549  while(doca2 < old_doca2){
550 
551  // if q==0 then the trajectory is a straight line anyway so
552  // exit the loop now so we drop to the linear extrapolation
553  // code below.
554  if( q == 0.0) break;
555 
556  // constrain to active volume
557  if(mypos_loc.z()<0.0 || mypos_loc.z()>625. || mypos_loc.Perp()>65.0) return 1;
558 
559  // remember the current doca2 and position
560  old_doca2=doca2;
561  last_pos = mypos_loc;
562 
563  // calculate new doca2 and position
564  Step(&mypos_loc);
565  doca2=mypos_loc.Perp2();
566  }
567 
568  // Do linear extrapolation to find POCA.
569  // We need to move in the (minus) momentum direction.
570  // Assume the beam line is in the (0,0,1) direction.
571  double p = mom.Mag();
572  if(p < 0.001) return true; // always fail for < 1MeV momentum
573 
574  DVector3 p_hat = (1.0/p)*mom;
575  double p_hat_z=p_hat.Z();
576 
577  // Step size along line starting at mypos_loc and pointing in the p_hat
578  // direction
579  double s=(p_hat_z*mypos_loc.Z()-p_hat.Dot(mypos_loc))/(1.-p_hat_z*p_hat_z);
580  // Add step in the negative momentum direction
581  mypos_loc+=s*p_hat;
582 
583  // Copy results back into user's DVector's and return success
584  mypos=mypos_loc;
585  mymom = -mom;
586  return false;
587 
588 // Original code
589 // // Set the starting parameters and start stepping!
590 // mymom=-1.0*mymom;
591 // SetStartingParams(q, &mypos, &mymom);
592 //
593 // DVector3 last_pos;
594 // double old_doca2=0.,doca2=1000.;
595 // do{
596 // old_doca2=doca2;
597 // last_pos = mypos;
598 //
599 // Step(&mypos);
600 // doca2=mypos.Perp2();
601 //
602 // if (doca2>old_doca2 && (mom.x()<0. || mom.y()<0.)){
603 // // Use a linear approximation to find the "true" POCA
604 // double pz=mom.z();
605 // if (fabs(pz)>0.001){
606 // double tx=mom.x()/pz;
607 // double ty=mom.y()/pz;
608 // double dz=-(mypos.x()*tx+mypos.y()*ty)/(tx*tx+ty*ty);
609 // mypos+=(dz/pz)*mom;
610 // }
611 // mymom=-1.*mom;
612 //
613 // return false;
614 // break;
615 // }
616 // }while (mypos.z()>0.0 && mypos.z()<625. && mypos.Perp()<65.0);
617 // // constrain to active volume
618 //
619 // return true;
620 }
621 
622 
623 //-----------------------
624 // SwimToRadius
625 //-----------------------
626 bool DMagneticFieldStepper::SwimToRadius(DVector3 &mypos, DVector3 &mymom, double R, double *pathlen)
627 {
628  /// Swim the particle from the point specified by the given position
629  /// and momentum until it crosses the specified radius R as measured
630  /// from the beamline.
631  ///
632  /// If a non-NULL value is passed for <i>pathlen</i> then the pathlength
633  /// of the track from the given starting position to the intersection point
634  /// is given.
635  ///
636  /// Particles will only be swum a distance of
637  /// MAX_SWIM_DIST (currently hardwired to 20 meters) along their
638  /// trajectory before returning boolean true indicating failure
639  /// to intersect the radius. This can happen if the particle's
640  /// momentum is too low to reach the radius.
641  ///
642  /// On success, a value of false is returned and the values in
643  /// pos and mom will be updated with the position and momentum at
644  /// the point of intersection with the radius.
645 
646  // Set the starting parameters and start stepping!
647  SetStartingParams(q, &mypos, &mymom);
648  double s = 0.0;
649  DVector3 last_pos;
650  do{
651  last_pos = mypos;
652 
653  s += Step(&mypos);
654  if(s>MAX_SWIM_DIST)return true;
655 
656  }while(mypos.Perp() < R);
657 
658  // At this point, the location where the track intersects the cyclinder
659  // is somewhere between last_pos and mypos. For simplicity, we're going
660  // to just find the intersection of the cylinder with the line that joins
661  // the 2 positions. We do this by working in the X/Y plane only and
662  // finding the value of "alpha" which is the fractional distance the
663  // intersection point is between last_pos and mypos. We'll then apply
664  // the alpha found in the 2D X/Y space to the 3D x/y/Z space to find
665  // the actual intersection point.
666  DVector2 x1(last_pos.X(), last_pos.Y());
667  DVector2 x2(mypos.X(), mypos.Y());
668  DVector2 dx = x2-x1;
669  double A = dx.Mod2();
670  double B = 2.0*(x1.X()*dx.X() + x1.Y()*dx.Y());
671  double C = x1.Mod2() - R*R;
672 
673  double alpha1 = (-B + sqrt(B*B-4.0*A*C))/(2.0*A);
674  double alpha2 = (-B - sqrt(B*B-4.0*A*C))/(2.0*A);
675  double alpha = alpha1;
676  if(alpha1<0.0 || alpha1>1.0)alpha=alpha2;
677  if(!isfinite(alpha))return true;
678 
679  DVector3 delta = mypos - last_pos;
680  mymom = mom;
681 
682  DVector3 pos1=last_pos+alpha1*delta;
683  DVector3 pos2=last_pos+alpha2*delta;
684 
685  // Choose the solution that is closer to the input point
686  if ((pos1-mypos).Mag()<(pos2-mypos).Mag()){
687  mypos=pos1;
688  // The value of s actually represents the pathlength
689  // to the outside point. Adjust it back to the
690  // intersection point (approximately).
691  s -= (1.0-alpha1)*delta.Mag();
692  }
693  else{
694  mypos=pos2;
695  // The value of s actually represents the pathlength
696  // to the outside point. Adjust it back to the
697  // intersection point (approximately).
698  s -= (1.0-alpha2)*delta.Mag();
699  }
700 
701  // Copy path length into caller's variable if supplied
702  if(pathlen)*pathlen=s;
703 
704  return false;
705 }
706 
707 //-----------------------
708 // DistToRadius
709 //-----------------------
711 {
712 
713  return false;
714 }
bool SwimToPlane(DVector3 &pos, DVector3 &mom, const DVector3 &origin, const DVector3 &norm, double *pathlen=NULL)
TVector2 DVector2
Definition: DVector2.h:9
TVector3 DVector3
Definition: DVector3.h:14
bool DistToRadius(DVector3 &pos, double R)
Double_t x[NCHANNELS]
Definition: st_tw_resols.C:39
#define y
bool SwimToRadius(DVector3 &pos, DVector3 &mom, double R, double *pathlen=NULL)
TF1 * f
Definition: FitGains.C:21
jerror_t SetStartingParams(double q, const DVector3 *x, const DVector3 *p)
void CalcDirs(double *Bvals=NULL)
const double alpha
DMagneticFieldStepper(const DMagneticFieldMap *map, double q=1.0)
bool SwimToPOCAtoBeamLine(double q, DVector3 &pos, DVector3 &mom)
double FastStep(double stepsize=0.0)
TH1D * py[NCHANNELS]
bool DistToPlane(DVector3 &pos, const DVector3 &origin, const DVector3 &norm)
double sqrt(double)
double sin(double)
#define MAX_SWIM_DIST
int grkuta_(double *CHARGE, double *STEP, double *VECT, double *VOUT, const DMagneticFieldMap *bfield)
Definition: grkuta.cc:270
double Step(DVector3 *newpos=NULL, DVector3 *B=NULL, double stepsize=0.0)
jerror_t SetMagneticFieldMap(const DMagneticFieldMap *map)
#define qBr2p
jerror_t SetStepSize(double step)
void GetDirs(DVector3 &xdir, DVector3 &ydir, DVector3 &zdir)