Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DQuickFit.cc
Go to the documentation of this file.
1 // $Id$
2 // Author: David Lawrence June 25, 2004
3 //
4 //
5 //
6 
7 #include <iostream>
8 #include <algorithm>
9 using namespace std;
10 
11 #include <math.h>
12 
13 #include "DQuickFit.h"
14 #include "DRiemannFit.h"
15 #define qBr2p 0.003 // conversion for converting q*B*r to GeV/c
16 #define Z_VERTEX 65.0
17 
18 // The following is for sorting hits by z
20  public:
21  bool operator()(DQFHit_t* const &a, DQFHit_t* const &b) const {
22  return a->z < b->z;
23  }
24 };
25 
26 bool DQFHitLessThanZ_C(DQFHit_t* const &a, DQFHit_t* const &b) {
27  return a->z < b->z;
28 }
29 
30 //-----------------
31 // DQuickFit (Constructor)
32 //-----------------
34 {
35  x0 = y0 = 0;
36  chisq = 0;
37  chisq_source = NOFIT;
38  bfield = NULL;
39 
40  c_origin=0.;
41  normal.SetXYZ(0.,0.,0.);
42 }
43 
44 //-----------------
45 // DQuickFit (Constructor)
46 //-----------------
48 {
49  Copy(fit);
50 }
51 //-----------------
52 // Copy
53 //-----------------
54 void DQuickFit::Copy(const DQuickFit &fit)
55 {
56  x0 = fit.x0;
57  y0 = fit.y0;
58  q = fit.q;
59  p = fit.p;
60  p_trans = fit.p_trans;
61  phi = fit.phi;
62  theta = fit.theta;
63  z_vertex = fit.z_vertex;
64  chisq = fit.chisq;
65  dzdphi = fit.dzdphi;
66  chisq_source = fit.chisq_source;
67  bfield = fit.GetMagneticFieldMap();
68  Bz_avg = fit.GetBzAvg();
69  z_mean = fit.GetZMean();
70  phi_mean = fit.GetPhiMean();
71 
72  const vector<DQFHit_t*> myhits = fit.GetHits();
73  for(unsigned int i=0; i<myhits.size(); i++){
74  DQFHit_t *a = new DQFHit_t;
75  *a = *myhits[i];
76  hits.push_back(a);
77  }
78 }
79 
80 //-----------------
81 // operator= (Assignment operator)
82 //-----------------
84 {
85  if(this == &fit)return *this;
86  Copy(fit);
87 
88  return *this;
89 }
90 
91 //-----------------
92 // DQuickFit (Destructor)
93 //-----------------
95 {
96  Clear();
97 }
98 
99 //-----------------
100 // AddHit
101 //-----------------
102 jerror_t DQuickFit::AddHit(float r, float phi, float z)
103 {
104  /// Add a hit to the list of hits using cylindrical coordinates
105 
106  return AddHitXYZ(r*cos(phi), r*sin(phi), z);
107 }
108 
109 //-----------------
110 // AddHitXYZ
111 //-----------------
112 jerror_t DQuickFit::AddHitXYZ(float x, float y, float z)
113 {
114  /// Add a hit to the list of hits useing Cartesian coordinates
115  DQFHit_t *hit = new DQFHit_t;
116  hit->x = x;
117  hit->y = y;
118  hit->z = z;
119  hit->chisq = 0.0;
120  hits.push_back(hit);
121 
122  return NOERROR;
123 }
124 
125 //-----------------
126 // PruneHit
127 //-----------------
128 jerror_t DQuickFit::PruneHit(int idx)
129 {
130  /// Remove the hit specified by idx from the list
131  /// of hits. The value of idx can be anywhere from
132  /// 0 to GetNhits()-1.
133  if(idx<0 || idx>=(int)hits.size())return VALUE_OUT_OF_RANGE;
134 
135  delete hits[idx];
136  hits.erase(hits.begin() + idx);
137 
138  return NOERROR;
139 }
140 
141 //-----------------
142 // Clear
143 //-----------------
144 jerror_t DQuickFit::Clear(void)
145 {
146  /// Remove all hits
147  for(unsigned int i=0; i<hits.size(); i++)delete hits[i];
148  hits.clear();
149 
150  return NOERROR;
151 }
152 
153 //-----------------
154 // PrintChiSqVector
155 //-----------------
156 jerror_t DQuickFit::PrintChiSqVector(void) const
157 {
158  /// Dump the latest chi-squared vector to the screen.
159  /// This prints the individual hits' chi-squared
160  /// contributions in the order in which the hits were
161  /// added. See PruneHits() for more detail.
162 
163  cout<<"Chisq vector from DQuickFit: (source=";
164  switch(chisq_source){
165  case NOFIT: cout<<"NOFIT"; break;
166  case CIRCLE: cout<<"CIRCLE"; break;
167  case TRACK: cout<<"TRACK"; break;
168  };
169  cout<<")"<<endl;
170  cout<<"----------------------------"<<endl;
171 
172  for(unsigned int i=0;i<hits.size();i++){
173  cout<<i<<" "<<hits[i]->chisq<<endl;
174  }
175  cout<<"Total: "<<chisq<<endl<<endl;
176 
177  return NOERROR;
178 }
179 
180 //-----------------
181 // FitCircle
182 //-----------------
183 jerror_t DQuickFit::FitCircle(void)
184 {
185  /// Fit the current set of hits to a circle
186  ///
187  /// This takes the hits which have been added thus far via one
188  /// of the AddHit() methods and fits them to a circle.
189  /// The alogorithm used here calculates the parameters directly using
190  /// a technique very much like linear regression. The key assumptions
191  /// are:
192  /// 1. The magnetic field is uniform and along z so that the projection
193  /// of the track onto the X/Y plane will fall on a circle
194  /// (this also implies no multiple-scattering or energy loss)
195  /// 2. The vertex is at the target center (i.e. 0,0 in the coordinate
196  /// system of the points passed to us.
197  ///
198  /// IMPORTANT: The value of phi which results from this assumes
199  /// the particle was positively charged. If the particle was
200  /// negatively charged, then phi will be 180 degrees off. To
201  /// correct this, one needs z-coordinate information to determine
202  /// the sign of the charge.
203  ///
204  /// ALSO IMPORTANT: This assumes a charge of +1 for the particle. If
205  /// the particle actually has a charge of +2, then the resulting
206  /// value of p_trans will be half of what it should be.
207 
208  float alpha=0.0, beta=0.0, gamma=0.0, deltax=0.0, deltay=0.0;
209  chisq_source = NOFIT; // in case we reutrn early
210 
211  // Loop over hits to calculate alpha, beta, gamma, and delta
212  // if a magnetic field map was given, use it to find average Z B-field
213  DQFHit_t *a = NULL;
214  for(unsigned int i=0;i<hits.size();i++){
215  a = hits[i];
216  float x=a->x;
217  float y=a->y;
218  alpha += x*x;
219  beta += y*y;
220  gamma += x*y;
221  deltax += x*(x*x+y*y)/2.0;
222  deltay += y*(x*x+y*y)/2.0;
223  }
224 
225  // Calculate x0,y0 - the center of the circle
226  double denom = alpha*beta-gamma*gamma;
227  if(fabs(denom)<1.0E-20)return UNRECOVERABLE_ERROR;
228  x0 = (deltax*beta-deltay*gamma)/denom;
229  //y0 = (deltay-gamma*x0)/beta;
230  y0 = (deltay*alpha-deltax*gamma)/denom;
231 
232  // Momentum depends on magnetic field. If bfield has been
233  // set, we should use it to determine an average value of Bz
234  // for this track. Otherwise, assume -2T.
235  // Also assume a singly charged track (i.e. q=+/-1)
236  // The sign of the charge will be determined below.
237  Bz_avg=-2.0;
238  q = +1.0;
239  r0 = sqrt(x0*x0 + y0*y0);
240  p_trans = q*Bz_avg*r0*qBr2p; // qBr2p converts to GeV/c
241  phi = atan2(y0,x0) - M_PI_2;
242  if(p_trans<0.0){
243  p_trans = -p_trans;
244  }
245  if(phi<0)phi+=2.0*M_PI;
246  if(phi>=2.0*M_PI)phi-=2.0*M_PI;
247 
248  // Calculate the chisq
249  ChisqCircle();
250  chisq_source = CIRCLE;
251 
252  return NOERROR;
253 }
254 
255 //-----------------
256 // ChisqCircle
257 //-----------------
259 {
260  /// Calculate the chisq for the hits and current circle
261  /// parameters.
262  /// NOTE: This does not return the chi2/dof, just the
263  /// raw chi2 with errs set to 1.0
264  chisq = 0.0;
265  for(unsigned int i=0;i<hits.size();i++){
266  DQFHit_t *a = hits[i];
267  float x = a->x - x0;
268  float y = a->y - y0;
269  float c = sqrt(x*x + y*y) - r0;
270  c *= c;
271  a->chisq = c;
272  chisq+=c;
273  }
274 
275  // Do NOT divide by DOF
276  return chisq;
277 }
278 
279 //-----------------
280 // FitCircleRiemann
281 //-----------------
283 {
284  /// This is a temporary solution for doing a Riemann circle fit.
285  /// It uses Simon's DRiemannFit class. This is not very efficient
286  /// since it creates a new DRiemann fit object, copies the hits
287  /// into it, and then copies the reults back to this DQuickFit
288  /// object every time this is called. At some point, the DRiemannFit
289  /// class will be merged into DQuickFit.
290 
291  chisq_source = NOFIT; // in case we reutrn early
292 
293  DRiemannFit rfit;
294  for(unsigned int i=0; i<hits.size(); i++){
295  DQFHit_t *hit = hits[i];
296  rfit.AddHitXYZ(hit->x, hit->y, hit->z);
297  }
298 
299  // Fake point at origin
300  double beam_var=BeamRMS*BeamRMS;
301  rfit.AddHit(0.,0.,Z_VERTEX,beam_var,beam_var,0.);
302 
303  jerror_t err = rfit.FitCircle(BeamRMS);
304  if(err!=NOERROR)return err;
305 
306  x0 = rfit.xc;
307  y0 = rfit.yc;
308  phi = rfit.phi;
309 
310  //r0 = sqrt(x0*x0+y0*y0);
311  r0=rfit.rc;
312 
313  rfit.GetPlaneParameters(c_origin,normal);
314 
315  // Momentum depends on magnetic field. If bfield has been
316  // set, we should use it to determine an average value of Bz
317  // for this track. Otherwise, assume -2T.
318  // Also assume a singly charged track (i.e. q=+/-1)
319  // The sign of the charge will be determined below.
320  Bz_avg=-2.0;
321  q = +1.0;
322  float r0 = sqrt(x0*x0 + y0*y0);
323  p_trans = q*Bz_avg*r0*qBr2p; // qBr2p converts to GeV/c
324  phi = atan2(y0,x0) - M_PI_2;
325  if(p_trans<0.0){
326  p_trans = -p_trans;
327  }
328  if(phi<0)phi+=2.0*M_PI;
329  if(phi>=2.0*M_PI)phi-=2.0*M_PI;
330 
331  // Calculate the chisq
332  ChisqCircle();
333  chisq_source = CIRCLE;
334 
335  return NOERROR;
336 }
337 
338 
339 //-----------------
340 // FitCircleStraightTrack
341 //-----------------
343 {
344  /// This is a last resort!
345  /// The circle fit can fail for high momentum tracks that are nearly
346  /// straight tracks. In these cases (when pt~2GeV or more) there
347  /// is not enough position resolution with wire positions only
348  /// to measure the curvature of the track.
349  /// We can though, fit the X/Y points with a straight line in order
350  /// to get phi and project out the stereo angles.
351  ///
352  /// For the radius of the circle (i.e. p_trans) we loop over momenta
353  /// from 1 to 9GeV and just use the one with the smallest chisq.
354 
355  // Average the x's and y's of the individual hits. We should be
356  // able to do this via linear regression, but I can't get it to
357  // work right now and I'm under the gun to get ready for a review
358  // so I take the easy way. Note that we don't average phi's since
359  // that will cause problems at the 0/2pi boundary.
360  double X=0.0, Y=0.0;
361  DQFHit_t *a = NULL;
362  for(unsigned int i=0;i<hits.size();i++){
363  a = hits[i];
364  double r = sqrt(pow((double)a->x,2.0) + pow((double)a->y, 2.0));
365  // weight by r to give outer points more influence. Note that
366  // we really are really weighting by r^2 since x and y already
367  // have a magnitude component.
368  X += a->x*r;
369  Y += a->y*r;
370  }
371  phi = atan2(Y,X);
372  if(phi<0)phi+=2.0*M_PI;
373  if(phi>=2.0*M_PI)phi-=2.0*M_PI;
374 
375  // Search the chi2 space for values for p_trans, x0, ...
376  SearchPtrans(9.0, 0.5);
377 
378 #if 0
379  // We do a simple linear regression here to find phi. This is
380  // simplified by the intercept being zero (i.e. the track
381  // passes through the beamline).
382  float Sxx=0.0, Syy=0.0, Sxy=0.0;
383  chisq_source = NOFIT; // in case we reutrn early
384 
385  // Loop over hits to calculate Sxx, Syy, and Sxy
386  DQFHit_t *a = NULL;
387  for(unsigned int i=0;i<hits.size();i++){
388  a = hits[i];
389  float x=a->x;
390  float y=a->y;
391  Sxx += x*x;
392  Syy += y*y;
393  Sxy += x*y;
394  }
395  double A = 2.0*Sxy;
396  double B = Sxx - Syy;
397  phi = B>A ? atan2(A,B)/2.0 : 1.0/atan2(B,A)/2.0;
398  if(phi<0)phi+=2.0*M_PI;
399  if(phi>=2.0*M_PI)phi-=2.0*M_PI;
400 #endif
401 
402  return NOERROR;
403 }
404 
405 //-----------------
406 // SearchPtrans
407 //-----------------
408 void DQuickFit::SearchPtrans(double ptrans_max, double ptrans_step)
409 {
410  /// Search the chi2 space as a function of the transverse momentum
411  /// for the minimal chi2. The values corresponding to the minmal
412  /// chi2 are left in chisq, x0, y0, r0, q, and p_trans.
413  ///
414  /// This does NOT optimize the value of p_trans. It simply
415  /// does a straight forward chisq calculation on a grid
416  /// and keeps the best one. It is intended for use in finding
417  /// a reasonable value for p_trans for straight tracks that
418  /// are contained to less than p_trans_max which is presumably
419  /// chosen based on a known &theta;.
420 
421  // Loop over several values for p_trans and calculate the
422  // chisq for each.
423  double min_chisq=1.0E6;
424  double min_x0=0.0, min_y0=0.0, min_r0=0.0;
425  for(double my_p_trans=ptrans_step; my_p_trans<=ptrans_max; my_p_trans+=ptrans_step){
426 
427  r0 = my_p_trans/(0.003*2.0);
428  double alpha, my_chisq;
429 
430  // q = +1
431  alpha = phi + M_PI_2;
432  x0 = r0*cos(alpha);
433  y0 = r0*sin(alpha);
434  my_chisq = ChisqCircle();
435  if(my_chisq<min_chisq){
436  min_chisq=my_chisq;
437  min_x0 = x0;
438  min_y0 = y0;
439  min_r0 = r0;
440  q = +1.0;
441  p_trans = my_p_trans;
442  }
443 
444  // q = -1
445  alpha = phi - M_PI_2;
446  x0 = r0*cos(alpha);
447  y0 = r0*sin(alpha);
448  my_chisq = ChisqCircle();
449  if(my_chisq<min_chisq){
450  min_chisq=my_chisq;
451  min_x0 = x0;
452  min_y0 = y0;
453  min_r0 = r0;
454  q = -1.0;
455  p_trans = my_p_trans;
456  }
457  }
458 
459  // Copy params from minimum chisq
460  x0 = min_x0;
461  y0 = min_y0;
462  r0 = min_r0;
463 }
464 
465 //-----------------
466 // QuickPtrans
467 //-----------------
469 {
470  /// Quickly calculate a value of p_trans by looking
471  /// for the hit furthest out and the hit closest
472  /// to half that distance. Those 2 hits along with the
473  /// origin are used to define a circle from which
474  /// p_trans is calculated.
475 
476  // Find hit with largest R
477  double R2max = 0.0;
478  DQFHit_t *hit_max = NULL;
479  for(unsigned int i=0; i<hits.size(); i++){
480  // use cross product to decide if hits is to left or right
481  double x = hits[i]->x;
482  double y = hits[i]->y;
483  double R2 = x*x + y*y;
484  if(R2>R2max){
485  R2max = R2;
486  hit_max = hits[i];
487  }
488  }
489 
490  // Bullet proof
491  if(!hit_max)return;
492 
493  // Find hit closest to half-way out
494  double Rmid = 0.0;
495  double Rmax = sqrt(R2max);
496  DQFHit_t *hit_mid = NULL;
497  for(unsigned int i=0; i<hits.size(); i++){
498  // use cross product to decide if hits is to left or right
499  double x = hits[i]->x;
500  double y = hits[i]->y;
501  double R = sqrt(x*x + y*y);
502  if(fabs(R-Rmax/2.0) < fabs(Rmid-Rmax/2.0)){
503  Rmid = R;
504  hit_mid = hits[i];
505  }
506  }
507 
508  // Bullet proof
509  if(!hit_mid)return;
510 
511  // Calculate p_trans from 3 points
512  double x1 = hit_mid->x;
513  double y1 = hit_mid->y;
514  double x2 = hit_max->x;
515  double y2 = hit_max->y;
516  double r2 = sqrt(x2*x2 + y2*y2);
517  double cos_phi = x2/r2;
518  double sin_phi = y2/r2;
519  double u1 = x1*cos_phi + y1*sin_phi;
520  double v1 = -x1*sin_phi + y1*cos_phi;
521  double u2 = x2*cos_phi + y2*sin_phi;
522  double u0 = u2/2.0;
523  double v0 = (u1*u1 + v1*v1 - u1*u2)/(2.0*v1);
524 
525  x0 = u0*cos_phi - v0*sin_phi;
526  y0 = u0*sin_phi + v0*cos_phi;
527  r0 = sqrt(x0*x0 + y0*y0);
528 
529  double B=-2.0;
530  p_trans = fabs(0.003*B*r0);
531  q = v1>0.0 ? -1.0:+1.0;
532 }
533 
534 //-----------------
535 // GuessChargeFromCircleFit
536 //-----------------
538 {
539  /// Adjust the sign of the charge (magnitude will stay 1) based on
540  /// whether the hits tend to be to the right or to the left of the
541  /// line going from the origin through the center of the circle.
542  /// If the sign is flipped, the phi angle will also be shifted by
543  /// +/- pi since the majority of hits are assumed to come from
544  /// outgoing tracks.
545  ///
546  /// This is just a guess since tracks can bend all the way
547  /// around and have hits that look exactly like tracks from an
548  /// outgoing particle of opposite charge. The final charge should
549  /// come from the sign of the dphi/dz slope.
550 
551  // Simply count the number of hits whose phi angle relative to the
552  // phi of the center of the circle are greater than pi.
553  unsigned int N=0;
554  for(unsigned int i=0; i<hits.size(); i++){
555  // use cross product to decide if hits is to left or right
556  double x = hits[i]->x;
557  double y = hits[i]->y;
558  if((x*y0 - y*x0) < 0.0)N++;
559  }
560 
561  // Check if more hits are negative and make sign negative if so.
562  if(N>hits.size()/2.0){
563  q = -1.0;
564  phi += M_PI;
565  if(phi>2.0*M_PI)phi-=2.0*M_PI;
566  }
567 
568  return NOERROR;
569 }
570 
571 //-----------------
572 // FitTrack
573 //-----------------
574 jerror_t DQuickFit::FitTrack(void)
575 {
576  /// Find theta, sign of electric charge, total momentum and
577  /// vertex z position.
578 
579  // Points must be in order of increasing Z
580  sort(hits.begin(), hits.end(), DQFHitLessThanZ_C);
581 
582  // Fit to circle to get circle's center
583  FitCircle();
584 
585  // The thing that is really needed is dphi/dz (where phi is the angle
586  // of the point as measured from the center of the circle, not the beam
587  // line). The relation between phi and z is linear so we use linear
588  // regression to find the slope (dphi/dz). The one complication is
589  // that phi is periodic so the value obtained via the x and y of a
590  // specific point can be off by an integral number of 2pis. Handle this
591  // by assuming the first point is measured before a full rotation
592  // has occurred. Subsequent points should always be within 2pi of
593  // the previous point so we just need to calculate the relative phi
594  // between succesive points and keep a running sum. We do this in
595  // the first loop were we find the mean z and phi values. The regression
596  // formulae are calculated in the second loop.
597 
598  // Calculate phi about circle center for each hit
599  Fill_phi_circle(hits, x0, y0);
600 
601  // Linear regression for z/phi relation
602  float Sxx=0.0, Syy=0.0, Sxy=0.0;
603  for(unsigned int i=0;i<hits.size();i++){
604  DQFHit_t *a = hits[i];
605  float deltaZ = a->z - z_mean;
606  float deltaPhi = a->phi_circle - phi_mean;
607  Syy += deltaZ*deltaZ;
608  Sxx += deltaPhi*deltaPhi;
609  Sxy += deltaZ*deltaPhi;
610  //cout<<__FILE__<<":"<<__LINE__<<" deltaZ="<<deltaZ<<" deltaPhi="<<deltaPhi<<" Sxy(i)="<<deltaZ*deltaPhi<<endl;
611  }
612  float dzdphi = Syy/Sxy;
613  z_vertex = z_mean - phi_mean*dzdphi;
614 //cout<<__FILE__<<":"<<__LINE__<<" z_mean="<<z_mean<<" phi_mean="<<phi_mean<<" dphidz="<<dphidz<<" Sxy="<<Sxy<<" Syy="<<Syy<<" z_vertex="<<z_vertex<<endl;
615 
616  // Fill in the rest of the parameters
617  return FillTrackParams();
618 }
619 
620 //-----------------
621 // FitTrack_FixedZvertex
622 //-----------------
623 jerror_t DQuickFit::FitTrack_FixedZvertex(float z_vertex)
624 {
625  /// Fit the points, but hold the z_vertex fixed at the specified value.
626  ///
627  /// This just calls FitCircle and FitLine_FixedZvertex to find all parameters
628  /// of the track
629 
630  // Fit to circle to get circle's center
631  FitCircle();
632 
633  // Fit to line in phi-z plane and return error
634  return FitLine_FixedZvertex(z_vertex);
635 }
636 
637 //-----------------
638 // FitLine_FixedZvertex
639 //-----------------
640 jerror_t DQuickFit::FitLine_FixedZvertex(float z_vertex)
641 {
642  /// Fit the points, but hold the z_vertex fixed at the specified value.
643  ///
644  /// This assumes FitCircle has already been called and the values
645  /// in x0 and y0 are valid.
646  ///
647  /// This just fits the phi-z angle by minimizing the chi-squared
648  /// using a linear regression technique. As it turns out, the
649  /// chi-squared weights points by their distances squared which
650  /// leads to a quadratic equation for cot(theta) (where theta is
651  /// the angle in the phi-z plane). To pick the right solution of
652  /// the quadratic equation, we pick the one closest to the linearly
653  /// weighted angle. One could argue that we should just use the
654  /// linear weighting here rather than the square weighting. The
655  /// choice depends though on how likely the "out-lier" points
656  /// are to really be from this track. If they are likely, to
657  /// be, then we would want to leverage their "longer" lever arms
658  /// with the squared weighting. If they are more likely to be bad
659  /// points, then we would want to minimize their influence with
660  /// a linear (or maybe even root) weighting. It is expected than
661  /// for our use, the points are all likely valid so we use the
662  /// square weighting.
663 
664  // Points must be in order of increasing Z
665  sort(hits.begin(), hits.end(), DQFHitLessThanZ_C);
666 
667  // Fit is being done for a fixed Z-vertex
668  this->z_vertex = z_vertex;
669 
670  // Calculate phi about circle center for each hit
671  Fill_phi_circle(hits, x0, y0);
672 
673  // Do linear regression on phi-Z
674  float Sx=0, Sy=0;
675  float Sxx=0, Syy=0, Sxy = 0;
676  float r0 = sqrt(x0*x0 + y0*y0);
677  for(unsigned int i=0; i<hits.size(); i++){
678  DQFHit_t *a = hits[i];
679 
680  float dz = a->z - z_vertex;
681  float dphi = a->phi_circle;
682  Sx += dz;
683  Sy += r0*dphi;
684  Syy += r0*dphi*r0*dphi;
685  Sxx += dz*dz;
686  Sxy += r0*dphi*dz;
687  }
688 
689  float k = (Syy-Sxx)/(2.0*Sxy);
690  float s = sqrt(k*k + 1.0);
691  float cot_theta1 = -k+s;
692  float cot_theta2 = -k-s;
693  float cot_theta_lin = Sx/Sy;
694  float cot_theta;
695  if(fabs(cot_theta_lin-cot_theta1) < fabs(cot_theta_lin-cot_theta2)){
696  cot_theta = cot_theta1;
697  }else{
698  cot_theta = cot_theta2;
699  }
700 
701  dzdphi = r0*cot_theta;
702 
703  // Fill in the rest of the paramters
704  return FillTrackParams();
705 }
706 
707 //------------------------------------------------------------------
708 // Fill_phi_circle
709 //------------------------------------------------------------------
710 jerror_t DQuickFit::Fill_phi_circle(vector<DQFHit_t*> hits, float x0, float y0)
711 {
712  float x_last = -x0;
713  float y_last = -y0;
714  float phi_last = 0.0;
715  z_mean = phi_mean = 0.0;
716  for(unsigned int i=0; i<hits.size(); i++){
717  DQFHit_t *a = hits[i];
718 
719  float dx = a->x - x0;
720  float dy = a->y - y0;
721  float dphi = atan2f(dx*y_last - dy*x_last, dx*x_last + dy*y_last);
722  float my_phi = phi_last +dphi;
723  a->phi_circle = my_phi;
724 
725  z_mean += a->z;
726  phi_mean += my_phi;
727 
728  x_last = dx;
729  y_last = dy;
730  phi_last = my_phi;
731  }
732  z_mean /= (float)hits.size();
733  phi_mean /= (float)hits.size();
734 
735  return NOERROR;
736 }
737 
738 //------------------------------------------------------------------
739 // FillTrackParams
740 //------------------------------------------------------------------
742 {
743  /// Fill in and tweak some parameters like q, phi, theta using
744  /// other values already set in the class. This is used by
745  /// both FitTrack() and FitTrack_FixedZvertex().
746 
747  float r0 = sqrt(x0*x0 + y0*y0);
748  theta = atan(r0/fabs(dzdphi));
749 
750  // The sign of the electric charge will be opposite that
751  // of dphi/dz. Also, the value of phi will be PI out of phase
752  if(dzdphi<0.0){
753  phi += M_PI;
754  if(phi<0)phi+=2.0*M_PI;
755  if(phi>=2.0*M_PI)phi-=2.0*M_PI;
756  }else{
757  q = -q;
758  }
759 
760  // Re-calculate chi-sq (needs to be done)
761  chisq_source = TRACK;
762 
763  // Up to now, the fit has assumed a forward going particle. In
764  // other words, if the particle is going backwards, the helix does
765  // actually still go through the points, but only if extended
766  // backward in time. We use the average z of the hits compared
767  // to the reconstructed vertex to determine if it was back-scattered.
768  if(z_mean<z_vertex){
769  // back scattered particle
770  theta = M_PI - theta;
771  phi += M_PI;
772  if(phi<0)phi+=2.0*M_PI;
773  if(phi>=2.0*M_PI)phi-=2.0*M_PI;
774  q = -q;
775  }
776 
777  // There is a problem with theta for data generated with a uniform
778  // field. The following factor is emprical until I can figure out
779  // what the source of the descrepancy is.
780  //theta += 0.1*pow((double)sin(theta),2.0);
781 
782  p = fabs(p_trans/sin(theta));
783 
784  return NOERROR;
785 }
786 
787 //------------------------------------------------------------------
788 // Print
789 //------------------------------------------------------------------
790 jerror_t DQuickFit::Print(void) const
791 {
792  cout<<"-- DQuickFit Params ---------------"<<endl;
793  cout<<" x0 = "<<x0<<endl;
794  cout<<" y0 = "<<y0<<endl;
795  cout<<" q = "<<q<<endl;
796  cout<<" p = "<<p<<endl;
797  cout<<" p_trans = "<<p_trans<<endl;
798  cout<<" phi = "<<phi<<endl;
799  cout<<" theta = "<<theta<<endl;
800  cout<<" z_vertex = "<<z_vertex<<endl;
801  cout<<" chisq = "<<chisq<<endl;
802  cout<<"chisq_source = ";
803  switch(chisq_source){
804  case NOFIT: cout<<"NOFIT"; break;
805  case CIRCLE: cout<<"CIRCLE"; break;
806  case TRACK: cout<<"TRACK"; break;
807  }
808  cout<<endl;
809  cout<<" Bz(avg) = "<<Bz_avg<<endl;
810 
811  return NOERROR;
812 }
813 
814 
815 //------------------------------------------------------------------
816 // Dump
817 //------------------------------------------------------------------
818 jerror_t DQuickFit::Dump(void) const
819 {
820  Print();
821 
822  for(unsigned int i=0;i<hits.size();i++){
823  DQFHit_t *v = hits[i];
824  cout<<" x="<<v->x<<" y="<<v->y<<" z="<<v->z;
825  cout<<" phi_circle="<<v->phi_circle<<" chisq="<<v->chisq<<endl;
826  }
827 
828  return NOERROR;
829 }
830 
831 //-------------------------------------------------------------------
832 //-------------------------------------------------------------------
833 //--------------------------- UNUSED --------------------------------
834 //-------------------------------------------------------------------
835 //-------------------------------------------------------------------
836 
837 
838 #if 0
839 
840 //-----------------
841 // AddHits
842 //-----------------
843 jerror_t DQuickFit::AddHits(int N, DVector3 *v)
844 {
845  /// Append a list of hits to the current list of hits using
846  /// DVector3 objects. The DVector3 objects are copied internally
847  /// so it is safe to delete the objects after calling AddHits()
848  /// For 2D hits, the value of z will be ignored.
849 
850  for(int i=0; i<N; i++, v++){
851  DVector3 *vec = new DVector3(*v);
852  if(vec)
853  hits.push_back(vec);
854  else
855  cerr<<__FILE__<<":"<<__LINE__<<" NULL vector in DQuickFit::AddHits. Hit dropped."<<endl;
856  }
857 
858  return NOERROR;
859 }
860 
861 //-----------------
862 // PruneHits
863 //-----------------
864 jerror_t DQuickFit::PruneHits(float chisq_limit)
865 {
866  /// Remove hits whose individual contribution to the chi-squared
867  /// value exceeds <i>chisq_limit</i>. The value of the individual
868  /// contribution is calculated like:
869  ///
870  /// \f$ r_0 = \sqrt{x_0^2 + y_0^2} \f$ <br>
871  /// \f$ r_i = \sqrt{(x_i-x_0)^2 + (y_i-y_0)^2} \f$ <br>
872  /// \f$ \chi_i^2 = (r_i-r_0)^2 \f$ <br>
873 
874  if(hits.size() != chisqv.size()){
875  cerr<<__FILE__<<":"<<__LINE__<<" hits and chisqv do not have the same number of rows!"<<endl;
876  cerr<<"Call FitCircle() or FitTrack() method first!"<<endl;
877 
878  return NOERROR;
879  }
880 
881  // Loop over these backwards to make it easier to
882  // handle the deletes
883  for(int i=chisqv.size()-1; i>=0; i--){
884  if(chisqv[i] > chisq_limit)PruneHit(i);
885  }
886 
887  return NOERROR;
888 }
889 
890 //-----------------
891 // PruneOutliers
892 //-----------------
893 jerror_t DQuickFit::PruneOutlier(void)
894 {
895  /// Remove the point which is furthest from the geometric
896  /// center of all the points in the X/Y plane.
897  ///
898  /// This just calculates the average x and y values of
899  /// registered hits. It finds the distance of every hit
900  /// with respect to the geometric mean and removes the
901  /// hit whose furthest from the mean.
902 
903  float X=0, Y=0;
904  for(unsigned int i=0;i<hits.size();i++){
905  DVector3 *v = hits[i];
906  X += v->x();
907  Y += v->y();
908  }
909  X /= (float)hits.size();
910  Y /= (float)hits.size();
911 
912  float max =0.0;
913  int idx = -1;
914  for(unsigned int i=0;i<hits.size();i++){
915  DVector3 *v = hits[i];
916  float x = v->x()-X;
917  float y = v->y()-Y;
918  float dist_sq = x*x + y*y; // we don't need to take sqrt just to find max
919  if(dist_sq>max){
920  max = dist_sq;
921  idx = i;
922  }
923  }
924  if(idx>=0)PruneHit(idx);
925 
926  return NOERROR;
927 }
928 
929 //-----------------
930 // PruneOutliers
931 //-----------------
932 jerror_t DQuickFit::PruneOutliers(int n)
933 {
934  /// Remove the n points which are furthest from the geometric
935  /// center of all the points in the X/Y plane.
936  ///
937  /// This just calls PruneOutlier() n times. Since the mean
938  /// can change each time, it should be recalculated after
939  /// every hit is removed.
940 
941  for(int i=0;i<n;i++)PruneOutlier();
942 
943  return NOERROR;
944 }
945 
946 //-----------------
947 // firstguess_curtis
948 //-----------------
949 jerror_t DCDC::firstguess_curtis(s_Cdc_trackhit_t *hits, int Npoints
950  , float &theta ,float &phi, float &p, float &q)
951 {
952  if(Npoints<3)return NOERROR;
953  // pick out 3 points to calculate the circle with
954  s_Cdc_trackhit_t *hit1, *hit2, *hit3;
955  hit1 = hits;
956  hit2 = &hits[Npoints/2];
957  hit3 = &hits[Npoints-1];
958 
959  float x1 = hit1->x, y1=hit1->y;
960  float x2 = hit2->x, y2=hit2->y;
961  float x3 = hit3->x, y3=hit3->y;
962 
963  float b = (x2*x2+y2*y2-x1*x1-y1*y1)/(2.0*(x2-x1));
964  b -= (x3*x3+y3*y3-x1*x1-y1*y1)/(2.0*(x3-x1));
965  b /= ((y1-y2)/(x1-x2)) - ((y1-y3)/(x1-x3));
966  float a = (x2*x2-y2*y2-x1*x1-y1*y1)/(2.0*(x2-x1));
967  a -= b*(y2-y1)/(x2-x1);
968 
969  // Above is the method from Curtis's crystal barrel note 93, pg 72
970  // Below here is just a copy of the code from David's firstguess
971  // routine above (after the x0,y0 calculation)
972  float x0=a, y0=b;
973 
974  // Momentum depends on magnetic field. Assume 2T for now.
975  // Also assume a singly charged track (i.e. q=+/-1)
976  // The sign of the charge will be deterined below.
977  float B=-2.0*0.593; // The 0.61 is empirical
978  q = +1.0;
979  float r0 = sqrt(x0*x0 + y0*y0);
980  float hbarc = 197.326;
981  float p_trans = q*B*r0/hbarc; // are these the right units?
982 
983  // Assuming points are ordered in increasing z, the sign of the
984  // cross-product between successive points will be the opposite
985  // sign of the charge. Since it's possible to have a few "bad"
986  // points, we don't want to rely on any one to determine this.
987  // The method we use is to sum cross-products of the first and
988  // middle points, the next-to-first and next-to-middle, etc.
989  float xprod_sum = 0.0;
990  int n_2 = Npoints/2;
991  s_Cdc_trackhit_t *v = hits;
992  s_Cdc_trackhit_t *v2=&hits[n_2];
993  for(int i=0;i<n_2;i++, v++, v2++){
994  xprod_sum += v->x*v2->y - v2->x*v->y;
995  }
996  if(xprod_sum>0.0)q = -q;
997 
998  // Phi is pi/2 out of phase with x0,y0. The sign of the phase difference
999  // depends on the charge
1000  phi = atan2(y0,x0);
1001  phi += q>0.0 ? -M_PI_2:M_PI_2;
1002 
1003  // Theta is determined by extrapolating the helix back to the target.
1004  // To do this, we need dphi/dz and a phi,z point. The easiest way to
1005  // get these is by a simple average (I guess).
1006  v = hits;
1007  v2=&v[1];
1008  float dzdphi =0.0;
1009  int Ndzdphipoints = 0;
1010  for(int i=0;i<Npoints-1;i++, v++, v2++){
1011  float myphi1 = atan2(v->y-y0, v->x-x0);
1012  float myphi2 = atan2(v2->y-y0, v2->x-x0);
1013  float mydzdphi = (v2->z-v->z)/(myphi2-myphi1);
1014  if(finite(mydzdphi)){
1015  dzdphi+=mydzdphi;
1016  Ndzdphipoints++;
1017  }
1018  }
1019  if(Ndzdphipoints){
1020  dzdphi/=(float)Ndzdphipoints;
1021  }
1022 
1023  theta = atan(r0/fabs(dzdphi));
1024  p = -p_trans/sin(theta);
1025 
1026  return NOERROR;
1027 }
1028 
1029 #endif
1030 
jerror_t FitCircleStraightTrack()
Definition: DQuickFit.cc:342
jerror_t FitCircle(void)
Definition: DQuickFit.cc:183
bool operator()(DQFHit_t *const &a, DQFHit_t *const &b) const
Definition: DQuickFit.cc:21
c Clear()
float GetBzAvg() const
Definition: DQuickFit.h:95
float y
Definition: DQuickFit.h:64
double phi
Definition: DRiemannFit.h:61
jerror_t FitCircleRiemann(double BeamRMS=0.100)
Definition: DQuickFit.cc:282
jerror_t AddHit(double r, double phi, double z)
Add a hit to the list of hits using cylindrical coordinates.
Definition: DRiemannFit.cc:22
TVector3 DVector3
Definition: DVector3.h:14
double Bz_avg
Double_t x[NCHANNELS]
Definition: st_tw_resols.C:39
locHist_ADCmulti Print()
#define c
double xc
Definition: DRiemannFit.h:56
#define y
float y0
Definition: DQuickFit.h:109
const vector< DQFHit_t * > GetHits() const
Definition: DQuickFit.h:92
jerror_t FitLine_FixedZvertex(float z_vertex)
Definition: DQuickFit.cc:640
float GetPhiMean() const
Definition: DQuickFit.h:97
jerror_t FillTrackParams(void)
Definition: DQuickFit.cc:741
ChiSqSourceType_t chisq_source
Definition: DQuickFit.h:116
float p
Definition: DQuickFit.h:111
#define X(str)
Definition: hddm-c.cpp:83
jerror_t Fill_phi_circle(vector< DQFHit_t * > hits, float x0, float y0)
Definition: DQuickFit.cc:710
double Rmax
Definition: bfield2root.cc:30
~DQuickFit()
Definition: DQuickFit.cc:94
DQuickFit(void)
Definition: DQuickFit.cc:33
float q
Definition: DQuickFit.h:110
jerror_t AddHitXYZ(float x, float y, float z)
Definition: DQuickFit.cc:112
double yc
Definition: DRiemannFit.h:56
const double alpha
jerror_t FitTrack_FixedZvertex(float z_vertex)
Definition: DQuickFit.cc:623
float x
Definition: DQuickFit.h:64
jerror_t PruneHit(int idx)
Definition: DQuickFit.cc:128
DQuickFit & operator=(const DQuickFit &fit)
Definition: DQuickFit.cc:83
float chisq
chi-sq contribution of this hit
Definition: DQuickFit.h:66
double rc
Definition: DRiemannFit.h:56
float p_trans
Definition: DQuickFit.h:111
float GetZMean() const
Definition: DQuickFit.h:96
void GetPlaneParameters(double &c, DVector3 &n)
Definition: DRiemannFit.h:49
const DMagneticFieldMap * GetMagneticFieldMap() const
Definition: DQuickFit.h:94
#define qBr2p
Definition: DQuickFit.cc:15
float x0
Definition: DQuickFit.h:109
jerror_t AddHitXYZ(double x, double y, double z)
Add a hit to the list of hits using Cartesian coordinates.
Definition: DRiemannFit.cc:29
#define Z_VERTEX
Definition: DQuickFit.cc:16
float chisq
Definition: DQuickFit.h:114
jerror_t Clear(void)
Definition: DQuickFit.cc:144
double sqrt(double)
double sin(double)
bool DQFHitLessThanZ_C(DQFHit_t *const &a, DQFHit_t *const &b)
Definition: DQuickFit.cc:26
double ChisqCircle(void)
Definition: DQuickFit.cc:258
void SearchPtrans(double ptrans_max=9.0, double ptrans_step=0.5)
Definition: DQuickFit.cc:408
void QuickPtrans(void)
Definition: DQuickFit.cc:468
float phi
Definition: DQuickFit.h:112
jerror_t FitTrack(void)
Definition: DQuickFit.cc:574
float theta
Definition: DQuickFit.h:112
jerror_t Dump(void) const
Definition: DQuickFit.cc:818
float phi_circle
phi angle relative to axis of helix
Definition: DQuickFit.h:65
jerror_t FitCircle(double rc)
Definition: DRiemannFit.cc:99
#define atan2f(x, y)
Definition: DHelicalFit.h:78
float z_vertex
Definition: DQuickFit.h:113
#define BeamRMS
float dzdphi
Definition: DQuickFit.h:115
jerror_t AddHit(float r, float phi, float z)
Definition: DQuickFit.cc:102
jerror_t Print(void) const
Definition: DQuickFit.cc:790
jerror_t GuessChargeFromCircleFit(void)
Definition: DQuickFit.cc:537
void Copy(const DQuickFit &fit)
Definition: DQuickFit.cc:54
jerror_t PrintChiSqVector(void) const
Definition: DQuickFit.cc:156
float z
point in lab coordinates
Definition: DQuickFit.h:64