Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DHelicalFit.cc
Go to the documentation of this file.
1 // Set of routines for fitting tracks in both the cdc and fdc assuming a
2 // uniform magnetic field. The track therefore is assumed to follow a helical
3 // path.
4 
5 #include <iostream>
6 #include <algorithm>
7 #include <cmath>
8 using namespace std;
9 
10 #include "DANA/DApplication.h"
11 #include <TDecompLU.h>
12 #include <math.h>
13 
14 #include "DHelicalFit.h"
15 #define qBr2p 0.003 // conversion for converting q*B*r to GeV/c
16 
17 #define ONE_THIRD 0.33333333333333333
18 #define SQRT3 1.73205080756887719
19 #define EPS 1e-8
20 #ifndef M_TWO_PI
21 #define M_TWO_PI 6.28318530717958647692
22 #endif
23 
24 // The following is for sorting hits by z
26  public:
27  bool operator()(DHFHit_t* const &a, DHFHit_t* const &b) const {
28  return a->z < b->z;
29  }
30 };
31 
32 inline bool DHFHitLessThanZ_C(DHFHit_t* const &a, DHFHit_t* const &b) {
33  return a->z < b->z;
34 }
36  return (a->z<b->z);
37 }
38 
40  const DHFProjection_t &b){
41  if(fabs(a.z - b.z) > 0.0)
42  return (a.z<b.z);
43  return (a.xy.Mod2() > b.xy.Mod2());
44 }
45 
46 
47 //-----------------
48 // DHelicalFit (Constructor)
49 //-----------------
51 {
52  x0 = 0., y0 = 0., r0=0., tanl=0., z_vertex = 0., phi=0., theta = 0.,dzdphi=0.;
53  h=1.;
54 
55  chisq = 0;
56  ndof=0;
57  chisq_source = NOFIT;
58  bfield = NULL;
59 
60  // For Riemann Fit
61  c_origin=0.;
62  normal.SetXYZ(0.,0.,0.);
63 }
64 
65 //-----------------
66 // DHelicalFit (Constructor)
67 //-----------------
69 {
70  Copy(fit);
71 }
72 
74 {
75  x0 = 0.0;
76  y0 = 0.0;
77  r0 = 0.0;
78  h = 1.0;
79  phi = 0.0;
80  theta = 0.0;
81  tanl = 0.0;
82  z_vertex = 0.0;
83  chisq = 0.0;
84  ndof = 0;
85  dzdphi = 0.0;
86  chisq_source = NOFIT;
87 
88  normal.SetXYZ(0.,0.,0.);
89  c_origin = 0.0;
90 
91  Clear();
92  //hits.clear();
93  z_mean = 0.0;
94  phi_mean = 0.0;
95 
96  N[0] = 0.0;
97  N[1] = 0.0;
98  N[2] = 0.0;
99 
100  xavg[0] = 0.0;
101  xavg[1] = 0.0;
102  xavg[2] = 0.0;
103 
104  var_avg = 0.0;
105 }
106 
107 //-----------------
108 // Copy
109 //-----------------
111 {
112  x0 = fit.x0;
113  y0 = fit.y0;
114  r0 = fit.r0;
115  h = fit.h;
116  tanl=fit.tanl;
117  phi = fit.phi;
118  theta = fit.theta;
119  z_vertex = fit.z_vertex;
120  chisq = fit.chisq;
121  ndof=fit.ndof;
122  dzdphi = fit.dzdphi;
123  chisq_source = fit.chisq_source;
124  z_mean = fit.GetZMean();
125  phi_mean = fit.GetPhiMean();
126 
127  const vector<DHFHit_t*> myhits = fit.GetHits();
128  for(unsigned int i=0; i<myhits.size(); i++){
129  DHFHit_t *a = new DHFHit_t;
130  *a = *myhits[i];
131  hits.push_back(a);
132  }
133 }
134 
135 //-----------------
136 // operator= (Assignment operator)
137 //-----------------
139 {
140  if(this == &fit)return *this;
141  Copy(fit);
142 
143  return *this;
144 }
145 
146 //-----------------
147 // DHelicalFit (Destructor)
148 //-----------------
150 {
151  Clear();
152 }
153 //-----------------
154 // AddHit -- add an FDC hit to the list
155 //-----------------
156 jerror_t DHelicalFit::AddHit(const DFDCPseudo *fdchit){
157  DHFHit_t *hit = new DHFHit_t;
158  hit->x = fdchit->xy.X();
159  hit->y = fdchit->xy.Y();
160  hit->z = fdchit->wire->origin.z();
161  hit->covx=fdchit->covxx;
162  hit->covy=fdchit->covyy;
163  hit->covxy=fdchit->covxy;
164  hit->chisq = 0.0;
165  hit->is_axial=false;
166 
167  double Phi=atan2(hit->y,hit->x);
168 
169  // Covariance matrix elements
170  double u=fdchit->w;
171  double v=fdchit->s;
172  double temp1=u*Phi-v;
173  double temp2=v*Phi+u;
174  double var_u=0.08333; // 1.0 cm^2/12
175  double var_v=0.0075;// 0.3*0.3 cm^2/12
176  double one_over_R2=1./fdchit->xy.Mod2();
177  hit->covrphi=one_over_R2*(var_v*temp1*temp1+var_u*temp2*temp2);
178  hit->covr=one_over_R2*(var_u*u*u+var_v*v*v);
179 
180  hits.push_back(hit);
181 
182  return NOERROR;
183 
184 }
185 
186 
187 //-----------------
188 // AddHit
189 //-----------------
190 jerror_t DHelicalFit::AddHit(float r, float phi, float z)
191 {
192  /// Add a hit to the list of hits using cylindrical coordinates
193 
194  return AddHitXYZ(r*cos(phi), r*sin(phi), z);
195 }
196 
197 //-----------------
198 // AddHitXYZ
199 //-----------------
200 jerror_t DHelicalFit::AddHitXYZ(float x, float y, float z)
201 {
202  /// Add a hit to the list of hits using Cartesian coordinates
203  DHFHit_t *hit = new DHFHit_t;
204  hit->x = x;
205  hit->y = y;
206  hit->z = z;
207  hit->covx=1.;
208  hit->covy=1.;
209  hit->covxy=0.;
210  hit->chisq = 0.0;
211  hit->is_axial=false;
212 
213  double Phi=atan2(hit->y,hit->x);
214  double cosPhi=cos(Phi);
215  double sinPhi=sin(Phi);
216  double Phi_cosPhi_minus_sinPhi=Phi*cosPhi-sinPhi;
217  double Phi_sinPhi_plus_cosPhi=Phi*sinPhi+cosPhi;
218  hit->covrphi=Phi_cosPhi_minus_sinPhi*Phi_cosPhi_minus_sinPhi*hit->covx
219  +Phi_sinPhi_plus_cosPhi*Phi_sinPhi_plus_cosPhi*hit->covy
220  +2.*Phi_sinPhi_plus_cosPhi*Phi_cosPhi_minus_sinPhi*hit->covxy;
221  hit->covr=cosPhi*cosPhi*hit->covx+sinPhi*sinPhi*hit->covy
222  +2.*sinPhi*cosPhi*hit->covxy;
223 
224  hits.push_back(hit);
225 
226  return NOERROR;
227 }
228 
229 // Add a hit to the list of hits using Cartesian coordinates
230 jerror_t DHelicalFit::AddHitXYZ(float x,float y, float z,float covx,
231  float covy, float covxy, bool is_axial){
232  DHFHit_t *hit = new DHFHit_t;
233  hit->x = x;
234  hit->y = y;
235  hit->z = z;
236  hit->covx=covx;
237  hit->covy=covy;
238  hit->covxy=covxy;
239  hit->is_axial=is_axial;
240 
241  double Phi=atan2(hit->y,hit->x);
242  double cosPhi=cos(Phi);
243  double sinPhi=sin(Phi);
244  double Phi_cosPhi_minus_sinPhi=Phi*cosPhi-sinPhi;
245  double Phi_sinPhi_plus_cosPhi=Phi*sinPhi+cosPhi;
246  hit->covrphi=Phi_cosPhi_minus_sinPhi*Phi_cosPhi_minus_sinPhi*hit->covx
247  +Phi_sinPhi_plus_cosPhi*Phi_sinPhi_plus_cosPhi*hit->covy
248  +2.*Phi_sinPhi_plus_cosPhi*Phi_cosPhi_minus_sinPhi*hit->covxy;
249  hit->covr=cosPhi*cosPhi*hit->covx+sinPhi*sinPhi*hit->covy
250  +2.*sinPhi*cosPhi*hit->covxy;
251 
252  hits.push_back(hit);
253 
254  return NOERROR;
255 }
256 
257 // Routine to add stereo hits once an initial circle fit has been done
258 jerror_t DHelicalFit::AddStereoHit(const DCDCWire *wire){
259  DVector3 origin = wire->origin;
260  DVector3 dir = wire->udir;
261  double dx=origin.x()-x0;
262  double dy=origin.y()-y0;
263  double ux=dir.x();
264  double uy=dir.y();
265  double temp1=ux*ux+uy*uy;
266  double temp2=ux*dy-uy*dx;
267  double b=-ux*dx-uy*dy;
268  double r0_sq=r0*r0;
269  double A=r0_sq*temp1-temp2*temp2;
270 
271  // Check that this wire intersects this circle
272  if(A<0.0) return VALUE_OUT_OF_RANGE; // line along wire does not intersect circle, ever.
273 
274  // Calculate intersection points for the two roots
275  double B = sqrt(A);
276  double dz1 = (b-B)/temp1;
277  double dz2 = (b+B)/temp1;
278 
279  // At this point we must decide which value of alpha to use.
280  // For now, we just use the value closest to zero (i.e. closest to
281  // the center of the wire).
282  double dz=dz1;
283  if (fabs(dz2)<fabs(dz1)){
284  dz=dz2;
285  }
286  // distance along wire relative to origin
287  double s=dz/cos(wire->stereo);
288 
289  // if(DEBUG_LEVEL>15)
290  _DBG_<<"s="<<s<<" ring="<<wire->ring<<" straw="<<wire->straw<<" stereo="<<wire->stereo<<endl;
291  if(fabs(s) > 0.5*wire->L) return VALUE_OUT_OF_RANGE; // if wire doesn't cross circle, skip hit
292 
293  // Compute the position for this hit
294  DVector3 pos = origin + s*dir;
295 
296  // Assume error on the radius of the circle is 10% of the radius and include
297  // the cell size contribution 1.6*1.6/12
298  double var_r=0.01*r0_sq+0.213;
299 
300  DHFHit_t *hit = new DHFHit_t;
301  hit->x=pos.x();
302  hit->y=pos.y();
303  hit->z=pos.z();
304  hit->covx=0.213; // place holder
305  hit->covy=0.213;
306  hit->covxy=0.;
307  hit->chisq=0.;
308  hit->is_axial=false;
309 
310  double Phi=atan2(hit->y,hit->x);
311  double cosPhi=cos(Phi);
312  double sinPhi=sin(Phi);
313  double Phi_cosPhi_minus_sinPhi=Phi*cosPhi-sinPhi;
314  double Phi_sinPhi_plus_cosPhi=Phi*sinPhi+cosPhi;
315  hit->covrphi=Phi_cosPhi_minus_sinPhi*Phi_cosPhi_minus_sinPhi*hit->covx
316  +Phi_sinPhi_plus_cosPhi*Phi_sinPhi_plus_cosPhi*hit->covy;
317  hit->covr=var_r;
318 
319  hits.push_back(hit);
320 
321  return NOERROR;
322 }
323 
324 
325 
326 
327 //-----------------
328 // PruneHit
329 //-----------------
330 jerror_t DHelicalFit::PruneHit(int idx)
331 {
332  /// Remove the hit specified by idx from the list
333  /// of hits. The value of idx can be anywhere from
334  /// 0 to GetNhits()-1.
335  if(idx<0 || idx>=(int)hits.size())return VALUE_OUT_OF_RANGE;
336 
337  delete hits[idx];
338  hits.erase(hits.begin() + idx);
339 
340  return NOERROR;
341 }
342 
343 //-----------------
344 // Clear
345 //-----------------
346 jerror_t DHelicalFit::Clear(void)
347 {
348  // Remove all hits
349  for(unsigned int i=0; i<hits.size(); i++)delete hits[i];
350  hits.clear();
351 
352  return NOERROR;
353 }
354 
355 //-----------------
356 // PrintChiSqVector
357 //-----------------
358 jerror_t DHelicalFit::PrintChiSqVector(void) const
359 {
360  /// Dump the latest chi-squared vector to the screen.
361  /// This prints the individual hits' chi-squared
362  /// contributions in the order in which the hits were
363  /// added. See PruneHits() for more detail.
364 
365  cout<<"Chisq vector from DHelicalFit: (source=";
366  switch(chisq_source){
367  case NOFIT: cout<<"NOFIT"; break;
368  case CIRCLE: cout<<"CIRCLE"; break;
369  case TRACK: cout<<"TRACK"; break;
370  };
371  cout<<")"<<endl;
372  cout<<"----------------------------"<<endl;
373 
374  for(unsigned int i=0;i<hits.size();i++){
375  cout<<i<<" "<<hits[i]->chisq<<endl;
376  }
377  cout<<"Total: "<<chisq<<endl<<endl;
378 
379  return NOERROR;
380 }
381 
382 //-----------------
383 // FitCircle
384 //-----------------
386 {
387  /// Fit the current set of hits to a circle
388  ///
389  /// This takes the hits which have been added thus far via one
390  /// of the AddHit() methods and fits them to a circle.
391  /// The alogorithm used here calculates the parameters directly using
392  /// a technique very much like linear regression. The key assumptions
393  /// are:
394  /// 1. The magnetic field is uniform and along z so that the projection
395  /// of the track onto the X/Y plane will fall on a circle
396  /// (this also implies no multiple-scattering or energy loss)
397  /// 2. The vertex is at the target center (i.e. 0,0 in the coordinate
398  /// system of the points passed to us.
399  ///
400  /// IMPORTANT: The value of phi which results from this assumes
401  /// the particle was positively charged. If the particle was
402  /// negatively charged, then phi will be 180 degrees off. To
403  /// correct this, one needs z-coordinate information to determine
404  /// the sign of the charge.
405 
406  float alpha=0.0, beta=0.0, gamma=0.0, deltax=0.0, deltay=0.0;
407  chisq_source = NOFIT; // in case we return early
408  size_t num_hits=hits.size();
409  ndof=num_hits-2;
410 
411  // Loop over hits to calculate alpha, beta, gamma, and delta
412  // if a magnetic field map was given, use it to find average Z B-field
413  DHFHit_t *a = NULL;
414  for(unsigned int i=0;i<num_hits;i++){
415  a = hits[i];
416  float x=a->x;
417  float y=a->y;
418  float x_sq=x*x;
419  float y_sq=y*y;
420  float x_sq_plus_y_sq=x_sq+y_sq;
421  alpha += x_sq;
422  beta += y_sq;
423  gamma += x*y;
424  deltax += 0.5*x*x_sq_plus_y_sq;
425  deltay += 0.5*y*x_sq_plus_y_sq;
426  }
427 
428  // Calculate x0,y0 - the center of the circle
429  double denom = alpha*beta-gamma*gamma;
430  if(fabs(denom)<1.0E-20)return UNRECOVERABLE_ERROR;
431  x0 = (deltax*beta-deltay*gamma)/denom;
432  y0 = (deltay*alpha-deltax*gamma)/denom;
433  r0 = sqrt(x0*x0 + y0*y0);
434 
435  phi = atan2(y0,x0) - M_PI_2;
436  if(phi<0)phi+=M_TWO_PI;
437  if(phi>=M_TWO_PI)phi-=M_TWO_PI;
438 
439  // Calculate the chisq
440  ChisqCircle();
441  chisq_source = CIRCLE;
442 
443  return NOERROR;
444 }
445 
446 //-----------------
447 // ChisqCircle
448 //-----------------
450 {
451  /// Calculate the chisq for the hits and current circle
452  /// parameters.
453  /// NOTE: This does not return the chi2/dof, just the
454  /// raw chi2
455  chisq = 0.0;
456  for(unsigned int i=0;i<hits.size();i++){
457  DHFHit_t *a = hits[i];
458  float x = a->x - x0;
459  float y = a->y - y0;
460  float x2=x*x,y2=y*y;
461  float r2=x2+y2;
462  float c = sqrt(r2) - r0;
463  c *= c;
464  double cov=(x2*a->covx+y2*a->covy+2.*x*y*a->covxy)/r2;
465  c/=cov;
466  a->chisq = c;
467  chisq+=c;
468  }
469 
470  // Do NOT divide by DOF
471  return chisq;
472 }
473 
474 //-----------------
475 // FitCircleRiemann
476 //-----------------
477 // Arguments are for inserting a "vertex" point
478 jerror_t DHelicalFit::FitCircleRiemann(float z_vertex,float BeamRMS)
479 {
480  chisq_source = NOFIT; // in case we return early
481 
482  // Fake point at origin
483  float beam_var=BeamRMS*BeamRMS;
484  AddHitXYZ(0.,0.,z_vertex,beam_var,beam_var,0.);
485 
486  jerror_t err = FitCircleRiemann();
487  if(err!=NOERROR)return err;
488 
489  // Number of degrees of freedom
490  ndof=hits.size()-3;
491 
492  phi=atan2(-x0,y0);
493  if(phi<0)phi+=M_TWO_PI;
494  if(phi>=M_TWO_PI)phi-=M_TWO_PI;
495 
496  // Normal vector for plane intersecting Riemann surface
497  normal.SetXYZ(N[0],N[1],N[2]);
498 
499  return NOERROR;
500 }
501 
502 //-----------------
503 // FitCircleRiemann
504 //-----------------
505 jerror_t DHelicalFit::FitCircleRiemann(float rc){
506 /// Riemann Circle fit: points on a circle in x,y project onto a plane cutting
507 /// the circular paraboloid surface described by (x,y,x^2+y^2). Therefore the
508 /// task of fitting points in (x,y) to a circle is transormed to the task of
509 /// fitting planes in (x,y, w=x^2+y^2) space
510 ///
511  size_t num_hits=hits.size();
512  DMatrix X(num_hits,3);
513  DMatrix Xavg(1,3);
514  DMatrix A(3,3);
515  // vector of ones
516  DMatrix OnesT(1,num_hits);
517  double W_sum=0.;
518  DMatrix W(num_hits,num_hits);
519 
520  // Make sure hit list is ordered in z
521  std::sort(hits.begin(),hits.end(),RiemannFit_hit_cmp);
522 
523  // Covariance matrix
524  DMatrix CRPhi(num_hits,num_hits);
525  for (unsigned int i=0;i<num_hits;i++){
526  CRPhi(i,i)=hits[i]->covrphi;
527  }
528 
529  // Apply a correction for non-normal track incidence if we already have a
530  // guess for rc.
531  if (rc>0.){
532  DMatrix C(num_hits,num_hits);
533  DMatrix S(num_hits,num_hits);
534  DMatrix CR(num_hits,num_hits);
535  for (unsigned int i=0;i<num_hits;i++){
536  S(i,i)=0.;
537  C(i,i)=1.;
538  CR(i,i)=hits[i]->covr;
539 
540  double rtemp=sqrt(hits[i]->x*hits[i]->x+hits[i]->y*hits[i]->y);
541  double stemp=rtemp/(4.*rc);
542  double ctemp=1.-stemp*stemp;
543  if (ctemp>0){
544  S(i,i)=stemp;
545  C(i,i)=sqrt(ctemp);
546  }
547  }
548  // Correction for non-normal incidence of track on FDC
549  CRPhi=C*CRPhi*C+S*CR*S;
550  }
551 
552  // The goal is to find the eigenvector corresponding to the smallest
553  // eigenvalue of the equation
554  // lambda=n^T (X^T W X - W_sum Xavg^T Xavg)n
555  // where n is the normal vector to the plane slicing the cylindrical
556  // paraboloid described by the parameterization (x,y,w=x^2+y^2),
557  // and W is the weight matrix, assumed for now to be diagonal.
558  // In the absence of multiple scattering, W_sum is the sum of all the
559  // diagonal elements in W.
560 
561  for (unsigned int i=0;i<num_hits;i++){
562  X(i,0)=hits[i]->x;
563  X(i,1)=hits[i]->y;
564  X(i,2)=hits[i]->x*hits[i]->x+hits[i]->y*hits[i]->y;
565  OnesT(0,i)=1.;
566  W(i,i)=1./CRPhi(i,i);
567  W_sum+=W(i,i);
568  }
569  Xavg=(1./W_sum)*(OnesT*(W*X));
570 
571  A=DMatrix(DMatrix::kTransposed,X)*(W*X)
572  -W_sum*(DMatrix(DMatrix::kTransposed,Xavg)*Xavg);
573  if(!A.IsValid())return UNRECOVERABLE_ERROR;
574 
575  // The characteristic equation is
576  // lambda^3+B2*lambda^2+lambda*B1+B0=0
577  //
578  double B2=-(A(0,0)+A(1,1)+A(2,2));
579  double B1=A(0,0)*A(1,1)-A(1,0)*A(0,1)+A(0,0)*A(2,2)-A(2,0)*A(0,2)
580  +A(1,1)*A(2,2)-A(2,1)*A(1,2);
581  double B0=-A.Determinant();
582  if(B0==0 || !isfinite(B0))return UNRECOVERABLE_ERROR;
583 
584  // The roots of the cubic equation are given by
585  // lambda1= -B2/3 + S+T
586  // lambda2= -B2/3 - (S+T)/2 + i sqrt(3)/2. (S-T)
587  // lambda3= -B2/3 - (S+T)/2 - i sqrt(3)/2. (S-T)
588  // where we define some temporary variables:
589  // S= (R+sqrt(Q^3+R^2))^(1/3)
590  // T= (R-sqrt(Q^3+R^2))^(1/3)
591  // Q=(3*B1-B2^2)/9
592  // R=(9*B2*B1-27*B0-2*B2^3)/54
593  // sum=S+T;
594  // diff=i*(S-T)
595  // We divide Q and R by a safety factor to prevent multiplying together
596  // enormous numbers that cause unreliable results.
597 
598  long double Q=(3.*B1-B2*B2)/9.e6;//4;
599  long double R=(9.*B2*B1-27.*B0-2.*B2*B2*B2)/54.e9;//6;
600  long double Q1=Q*Q*Q+R*R;
601  if (Q1<0) Q1=sqrtl(-Q1);
602  else{
603  return VALUE_OUT_OF_RANGE;
604  }
605 
606  // DeMoivre's theorem for fractional powers of complex numbers:
607  // (r*(cos(theta)+i sin(theta)))^(p/q)
608  // = r^(p/q)*(cos(p*theta/q)+i sin(p*theta/q))
609  //
610  //double temp=100.*pow(R*R+Q1*Q1,0.16666666666666666667);
611  long double temp=1000.*sqrtl(cbrtl(R*R+Q1*Q1));
612  long double theta1=ONE_THIRD*atan2l(Q1,R);
613  long double sum_over_2=temp*cosl(theta1);
614  long double diff_over_2=-temp*sinl(theta1);
615  // Third root
616  long double lambda_min=-ONE_THIRD*B2-sum_over_2+SQRT3*diff_over_2;
617 
618  // Calculate the (normal) eigenvector corresponding to the eigenvalue lambda
619  double A11_minus_lambda_min=A(1,1)-lambda_min;
620  N[0]=1.;
621  N[1]=(A(1,0)*A(0,2)-(A(0,0)-lambda_min)*A(1,2))
622  /(A(0,1)*A(2,1)-A11_minus_lambda_min*A(0,2));
623  N[2]=(A(2,0)*A11_minus_lambda_min-A(1,0)*A(2,1))
624  /(A(1,2)*A(2,1)-(A(2,2)-lambda_min)*A11_minus_lambda_min);
625 
626  // Normalize: n1^2+n2^2+n3^2=1
627  double denom=sqrt(N[0]*N[0]+N[1]*N[1]+N[2]*N[2]);
628  for (int i=0;i<3;i++){
629  N[i]/=denom;
630  }
631 
632  // Distance to origin
633  c_origin=-(N[0]*Xavg(0,0)+N[1]*Xavg(0,1)+N[2]*Xavg(0,2));
634 
635  // Center and radius of the circle
636  double one_over_2Nz=1./(2.*N[2]);
637  //x0=-N[0]/2./N[2];
638  //y0=-N[1]/2./N[2];
639  //r0=sqrt(1.-N[2]*N[2]-4.*c_origin*N[2])/2./fabs(N[2]);
640  x0=-N[0]*one_over_2Nz;
641  y0=-N[1]*one_over_2Nz;
642  r0=sqrt(1.-N[2]*N[2]-4.*c_origin*N[2])*fabs(one_over_2Nz);
643 
644  // Phi value at "vertex"
645  phi=atan2(-x0,y0);
646  if(phi<0)phi+=M_TWO_PI;
647  if(phi>=M_TWO_PI)phi-=M_TWO_PI;
648 
649  // Calculate the chisq
650  ChisqCircle();
651  chisq_source = CIRCLE;
652  ndof=hits.size()-3;
653 
654  return NOERROR;
655 }
656 
657 //-----------------
658 // FitLineRiemann
659 //-----------------
661 /// Riemann Line fit: linear regression of s on z to determine the tangent of
662 /// the dip angle and the z position of the closest approach to the beam line.
663 /// Computes intersection points along the helical path.
664 /// Note: this implementation assumes that the error in the z-position is
665 /// negligible; practically speaking, this means it should only be used for FDC
666 /// hits...
667  size_t num_hits=hits.size();
668 
669  // Fill vector of intersection points
670  double denom= N[0]*N[0]+N[1]*N[1];
671  // projection vector
672  vector<DHFProjection_t>projections;
673  for (unsigned int m=0;m<num_hits;m++){
674  if (hits[m]->is_axial) continue;
675 
676  double r2=hits[m]->x*hits[m]->x+hits[m]->y*hits[m]->y;
677  double numer=c_origin+r2*N[2];
678  double ratio=numer/denom;
679  double x_int0=-N[0]*ratio;
680  double y_int0=-N[1]*ratio;
681  double temp=denom*r2-numer*numer;
682  if (temp<0){ // Skip point if the intersection gives nonsense
683  //_DBG_ << "Bad?" <<endl;
684  continue;
685  }
686  temp=sqrt(temp)/denom;
687 
688  // Store projection data in a temporary structure
689  DHFProjection_t temp_proj;
690  temp_proj.z=hits[m]->z;
691  temp_proj.covR=hits[m]->covr;
692 
693  // Choose sign of square root based on proximity to actual measurements
694  double deltax=N[1]*temp;
695  double deltay=-N[0]*temp;
696  double x1=x_int0+deltax;
697  double y1=y_int0+deltay;
698  double x2=x_int0-deltax;
699  double y2=y_int0-deltay;
700  double diffx1=x1-hits[m]->x;
701  double diffy1=y1-hits[m]->y;
702  double diffx2=x2-hits[m]->x;
703  double diffy2=y2-hits[m]->y;
704  if (diffx1*diffx1+diffy1*diffy1 > diffx2*diffx2+diffy2*diffy2){
705  temp_proj.xy=DVector2(x2,y2);
706  }
707  else{
708  temp_proj.xy=DVector2(x1,y1);
709  }
710  projections.push_back(temp_proj);
711  }
712  if (projections.size()==0) return RESOURCE_UNAVAILABLE;
713  sort(projections.begin(),projections.end(),DHFProjection_cmp);
714 
715  // Linear regression to find z0, tanl
716  unsigned int n=projections.size();
717  double sumv=0.,sumx=0.,sumy=0.,sumxx=0.,sumxy=0.;
718  double sperp=0.,sperp_old=0., ratio=0, Delta;
719  double z=0.;
720  DVector2 old_proj=projections[0].xy;
721  double two_r0=2.*r0;
722  for (unsigned int k=0;k<n;k++){
723  sperp_old=sperp;
724  double chord=(projections[k].xy-old_proj).Mod();
725  ratio=chord/two_r0;
726 
727  // Make sure the argument for the arcsin does not go out of range...
728  double ds=(ratio>1)? two_r0*M_PI_2 : two_r0*asin(ratio);
729  sperp=sperp_old+ds;
730  z=projections[k].z;
731 
732  double weight=1./projections[k].covR;
733  sumv+=weight;
734  sumy+=sperp*weight;
735  sumx+=z*weight;
736  sumxx+=z*z*weight;
737  sumxy+=sperp*z*weight;
738 
739  // Store the current x and y projection values
740  old_proj=projections[k].xy;
741  }
742  Delta=sumv*sumxx-sumx*sumx;
743  double tanl_denom=sumv*sumxy-sumy*sumx;
744  if (fabs(Delta)<EPS || fabs(tanl_denom)<EPS) return VALUE_OUT_OF_RANGE;
745 
746  // Track parameters tan(lambda) and z-vertex
747  tanl=Delta/tanl_denom;
748 
749  double chord=projections[0].xy.Mod();
750  ratio=chord/two_r0;
751  sperp=(ratio>1? two_r0*M_PI_2 : two_r0*asin(ratio));
752  z_vertex=projections[0].z-sperp*tanl;
753 
754  theta=M_PI_2-atan(tanl);
755 
756  return NOERROR;
757 }
758 
759 //-----------------
760 // FitCircleStraightTrack
761 //-----------------
763 {
764  /// This is a last resort!
765  /// The circle fit can fail for high momentum tracks that are nearly
766  /// straight tracks. In these cases (when pt~2GeV or more) there
767  /// is not enough position resolution with wire positions only
768  /// to measure the curvature of the track.
769  /// We can though, fit the X/Y points with a straight line in order
770  /// to get phi and project out the stereo angles.
771  ///
772  /// For the radius of the circle (i.e. p_trans) we loop over momenta
773  /// from 1 to 9GeV and just use the one with the smallest chisq.
774 
775  // Average the x's and y's of the individual hits. We should be
776  // able to do this via linear regression, but I can't get it to
777  // work right now and I'm under the gun to get ready for a review
778  // so I take the easy way. Note that we don't average phi's since
779  // that will cause problems at the 0/2pi boundary.
780  double X=0.0, Y=0.0;
781  DHFHit_t *a = NULL;
782  size_t num_hits=hits.size();
783  for(unsigned int i=0;i<num_hits;i++){
784  a = hits[i];
785  double r = sqrt(a->x*a->x+a->y*a->y);
786  // weight by r to give outer points more influence. Note that
787  // we really are really weighting by r^2 since x and y already
788  // have a magnitude component.
789  X += a->x*r;
790  Y += a->y*r;
791  }
792  phi = atan2(Y,X);
793  if(phi<0)phi+=M_TWO_PI;
794  if(phi>=M_TWO_PI)phi-=M_TWO_PI;
795 
796  // Search the chi2 space for values for x0, y0, ...
797  SearchPtrans(9.0, 0.5);
798 
799 #if 0
800  // We do a simple linear regression here to find phi. This is
801  // simplified by the intercept being zero (i.e. the track
802  // passes through the beamline).
803  float Sxx=0.0, Syy=0.0, Sxy=0.0;
804  chisq_source = NOFIT; // in case we return early
805 
806  // Loop over hits to calculate Sxx, Syy, and Sxy
807  DHFHit_t *a = NULL;
808  for(unsigned int i=0;i<num_hits;i++){
809  a = hits[i];
810  float x=a->x;
811  float y=a->y;
812  Sxx += x*x;
813  Syy += y*y;
814  Sxy += x*y;
815  }
816  double A = 2.0*Sxy;
817  double B = Sxx - Syy;
818  phi = B>A ? atan2(A,B)/2.0 : 1.0/atan2(B,A)/2.0;
819  if(phi<0)phi+=M_TWO_PI;
820  if(phi>=M_TWO_PI)phi-=M_TWO_PI;
821 #endif
822 
823  return NOERROR;
824 }
825 
826 //-----------------
827 // SearchPtrans
828 //-----------------
829 void DHelicalFit::SearchPtrans(double ptrans_max, double ptrans_step)
830 {
831  /// Search the chi2 space as a function of the transverse momentum
832  /// for the minimal chi2. The values corresponding to the minmal
833  /// chi2 are left in chisq, x0, y0, r0, q, and p_trans.
834  ///
835  /// This does NOT optimize the value of p_trans. It simply
836  /// does a straight forward chisq calculation on a grid
837  /// and keeps the best one. It is intended for use in finding
838  /// a reasonable value for p_trans for straight tracks that
839  /// are contained to less than p_trans_max which is presumably
840  /// chosen based on a known &theta;.
841 
842  // Loop over several values for p_trans and calculate the
843  // chisq for each.
844  double min_chisq=1.0E6;
845  double min_x0=0.0, min_y0=0.0, min_r0=0.0;
846  for(double my_p_trans=ptrans_step; my_p_trans<=ptrans_max; my_p_trans+=ptrans_step){
847 
848  r0 = my_p_trans/(0.003*2.0);
849  double alpha, my_chisq;
850 
851  // h = +1
852  alpha = phi + M_PI_2;
853  x0 = r0*cos(alpha);
854  y0 = r0*sin(alpha);
855  my_chisq = ChisqCircle();
856  if(my_chisq<min_chisq){
857  min_chisq=my_chisq;
858  min_x0 = x0;
859  min_y0 = y0;
860  min_r0 = r0;
861  h = +1.0;
862  }
863 
864  // h = -1
865  alpha = phi - M_PI_2;
866  x0 = r0*cos(alpha);
867  y0 = r0*sin(alpha);
868  my_chisq = ChisqCircle();
869  if(my_chisq<min_chisq){
870  min_chisq=my_chisq;
871  min_x0 = x0;
872  min_y0 = y0;
873  min_r0 = r0;
874  h = -1.0;
875  }
876  }
877 
878  // Copy params from minimum chisq
879  x0 = min_x0;
880  y0 = min_y0;
881  r0 = min_r0;
882 }
883 
884 //-----------------
885 // GuessChargeFromCircleFit
886 //-----------------
888 {
889  /// Adjust the sign of the charge (magnitude will stay 1) based on
890  /// whether the hits tend to be to the right or to the left of the
891  /// line going from the origin through the center of the circle.
892  /// If the sign is flipped, the phi angle will also be shifted by
893  /// +/- pi since the majority of hits are assumed to come from
894  /// outgoing tracks.
895  ///
896  /// This is just a guess since tracks can bend all the way
897  /// around and have hits that look exactly like tracks from an
898  /// outgoing particle of opposite charge. The final charge should
899  /// come from the sign of the dphi/dz slope.
900 
901  // Simply count the number of hits whose phi angle relative to the
902  // phi of the center of the circle are greater than pi.
903  unsigned int N=0;
904  for(unsigned int i=0; i<hits.size(); i++){
905  // use cross product to decide if hits is to left or right
906  double x = hits[i]->x;
907  double y = hits[i]->y;
908  if((x*y0 - y*x0) < 0.0)N++;
909  }
910 
911  // Check if more hits are negative and make sign negative if so.
912  if(N>hits.size()/2){
913  h = -1.0;
914  phi += M_PI;
915  if(phi>M_TWO_PI)phi-=M_TWO_PI;
916  }
917 
918  return NOERROR;
919 }
920 
921 //-----------------
922 // FitTrack
923 //-----------------
924 jerror_t DHelicalFit::FitTrack(void)
925 {
926  /// Find theta, sign of electric charge, total momentum and
927  /// vertex z position.
928 
929  // Points must be in order of increasing Z
930  sort(hits.begin(), hits.end(), DHFHitLessThanZ_C);
931 
932  // Fit to circle to get circle's center
933  FitCircle();
934 
935  // The thing that is really needed is dphi/dz (where phi is the angle
936  // of the point as measured from the center of the circle, not the beam
937  // line). The relation between phi and z is linear so we use linear
938  // regression to find the slope (dphi/dz). The one complication is
939  // that phi is periodic so the value obtained via the x and y of a
940  // specific point can be off by an integral number of 2pis. Handle this
941  // by assuming the first point is measured before a full rotation
942  // has occurred. Subsequent points should always be within 2pi of
943  // the previous point so we just need to calculate the relative phi
944  // between succesive points and keep a running sum. We do this in
945  // the first loop were we find the mean z and phi values. The regression
946  // formulae are calculated in the second loop.
947 
948  // Calculate phi about circle center for each hit
949  Fill_phi_circle(hits, x0, y0);
950 
951  // Linear regression for z/phi relation
952  float Sxx=0.0, Syy=0.0, Sxy=0.0;
953  for(unsigned int i=0;i<hits.size();i++){
954  DHFHit_t *a = hits[i];
955  float deltaZ = a->z - z_mean;
956  float deltaPhi = a->phi_circle - phi_mean;
957  Syy += deltaZ*deltaZ;
958  Sxx += deltaPhi*deltaPhi;
959  Sxy += deltaZ*deltaPhi;
960  //cout<<__FILE__<<":"<<__LINE__<<" deltaZ="<<deltaZ<<" deltaPhi="<<deltaPhi<<" Sxy(i)="<<deltaZ*deltaPhi<<endl;
961  }
962  float dzdphi = Syy/Sxy;
963  z_vertex = z_mean - phi_mean*dzdphi;
964 //cout<<__FILE__<<":"<<__LINE__<<" z_mean="<<z_mean<<" phi_mean="<<phi_mean<<" dphidz="<<dphidz<<" Sxy="<<Sxy<<" Syy="<<Syy<<" z_vertex="<<z_vertex<<endl;
965 
966  // Fill in the rest of the parameters
967  return FillTrackParams();
968 }
969 
970 //-----------------
971 // FitTrackRiemann
972 //-----------------
973 jerror_t DHelicalFit::FitTrackRiemann(float rc_input){
974  jerror_t error=FitCircleRiemann(rc_input);
975  if (error!=NOERROR) return error;
976  error=FitLineRiemann();
977  FindSenseOfRotation();
978 
979  return error;
980 }
981 
982 
983 jerror_t DHelicalFit::FitCircleAndLineRiemann(float rc_input){
984  jerror_t error=FitCircleRiemann(rc_input);
985  if (error!=NOERROR) return error;
986  error=FitLineRiemann();
987 
988  return error;
989 }
990 
991 
992 
993 
994 //-----------------
995 // FitTrack_FixedZvertex
996 //-----------------
997 jerror_t DHelicalFit::FitTrack_FixedZvertex(float z_vertex)
998 {
999  /// Fit the points, but hold the z_vertex fixed at the specified value.
1000  ///
1001  /// This just calls FitCircle and FitLine_FixedZvertex to find all parameters
1002  /// of the track
1003 
1004  // Fit to circle to get circle's center
1005  FitCircle();
1006 
1007  // Fit to line in phi-z plane and return error
1008  return FitLine_FixedZvertex(z_vertex);
1009 }
1010 
1011 //-----------------
1012 // FitLine_FixedZvertex
1013 //-----------------
1014 jerror_t DHelicalFit::FitLine_FixedZvertex(float z_vertex)
1015 {
1016  /// Fit the points, but hold the z_vertex fixed at the specified value.
1017  ///
1018  /// This assumes FitCircle has already been called and the values
1019  /// in x0 and y0 are valid.
1020  ///
1021  /// This just fits the phi-z angle by minimizing the chi-squared
1022  /// using a linear regression technique. As it turns out, the
1023  /// chi-squared weights points by their distances squared which
1024  /// leads to a quadratic equation for cot(theta) (where theta is
1025  /// the angle in the phi-z plane). To pick the right solution of
1026  /// the quadratic equation, we pick the one closest to the linearly
1027  /// weighted angle. One could argue that we should just use the
1028  /// linear weighting here rather than the square weighting. The
1029  /// choice depends though on how likely the "out-lier" points
1030  /// are to really be from this track. If they are likely, to
1031  /// be, then we would want to leverage their "longer" lever arms
1032  /// with the squared weighting. If they are more likely to be bad
1033  /// points, then we would want to minimize their influence with
1034  /// a linear (or maybe even root) weighting. It is expected than
1035  /// for our use, the points are all likely valid so we use the
1036  /// square weighting.
1037 
1038  // Points must be in order of increasing Z
1039  sort(hits.begin(), hits.end(), DHFHitLessThanZ_C);
1040 
1041  // Fit is being done for a fixed Z-vertex
1042  this->z_vertex = z_vertex;
1043 
1044  // Calculate phi about circle center for each hit
1045  Fill_phi_circle(hits, x0, y0);
1046 
1047  // Do linear regression on phi-Z
1048  float Sx=0, Sy=0;
1049  float Sxx=0, Syy=0, Sxy = 0;
1050  float r0 = sqrt(x0*x0 + y0*y0);
1051  for(unsigned int i=0; i<hits.size(); i++){
1052  DHFHit_t *a = hits[i];
1053 
1054  float dz = a->z - z_vertex;
1055  float dphi = a->phi_circle;
1056  Sx += dz;
1057  Sy += r0*dphi;
1058  Syy += r0*dphi*r0*dphi;
1059  Sxx += dz*dz;
1060  Sxy += r0*dphi*dz;
1061  }
1062 
1063  float k = (Syy-Sxx)/(2.0*Sxy);
1064  float s = sqrt(k*k + 1.0);
1065  float cot_theta1 = -k+s;
1066  float cot_theta2 = -k-s;
1067  float cot_theta_lin = Sx/Sy;
1068  float cot_theta;
1069  if(fabs(cot_theta_lin-cot_theta1) < fabs(cot_theta_lin-cot_theta2)){
1070  cot_theta = cot_theta1;
1071  }else{
1072  cot_theta = cot_theta2;
1073  }
1074 
1075  dzdphi = r0*cot_theta;
1076 
1077  // Fill in the rest of the paramters
1078  return FillTrackParams();
1079 }
1080 
1081 //------------------------------------------------------------------
1082 // Fill_phi_circle
1083 //------------------------------------------------------------------
1084 jerror_t DHelicalFit::Fill_phi_circle(vector<DHFHit_t*> hits, float x0, float y0)
1085 {
1086  float x_last = -x0;
1087  float y_last = -y0;
1088  float phi_last = 0.0;
1089  z_mean = phi_mean = 0.0;
1090  for(unsigned int i=0; i<hits.size(); i++){
1091  DHFHit_t *a = hits[i];
1092 
1093  float dx = a->x - x0;
1094  float dy = a->y - y0;
1095  float dphi = atan2f(dx*y_last - dy*x_last, dx*x_last + dy*y_last);
1096  float my_phi = phi_last +dphi;
1097  a->phi_circle = my_phi;
1098 
1099  z_mean += a->z;
1100  phi_mean += my_phi;
1101 
1102  x_last = dx;
1103  y_last = dy;
1104  phi_last = my_phi;
1105  }
1106  z_mean /= (float)hits.size();
1107  phi_mean /= (float)hits.size();
1108 
1109  return NOERROR;
1110 }
1111 
1112 //------------------------------------------------------------------
1113 // FillTrackParams
1114 //------------------------------------------------------------------
1116 {
1117  /// Fill in and tweak some parameters like q, phi, theta using
1118  /// other values already set in the class. This is used by
1119  /// both FitTrack() and FitTrack_FixedZvertex().
1120 
1121  float r0 = sqrt(x0*x0 + y0*y0);
1122  theta = atan(r0/fabs(dzdphi));
1123 
1124  // the sense of rotation about the z axis will be opposite that
1125  // of dphi/dz. Also, the value of phi will be PI out of phase
1126  if(dzdphi<0.0){
1127  phi += M_PI;
1128  if(phi<0)phi+=M_TWO_PI;
1129  if(phi>=M_TWO_PI)phi-=M_TWO_PI;
1130  }else{
1131  h = -h;
1132  }
1133 
1134  // Re-calculate chi-sq (needs to be done)
1135  chisq_source = TRACK;
1136 
1137  // Up to now, the fit has assumed a forward going particle. In
1138  // other words, if the particle is going backwards, the helix does
1139  // actually still go through the points, but only if extended
1140  // backward in time. We use the average z of the hits compared
1141  // to the reconstructed vertex to determine if it was back-scattered.
1142  if(z_mean<z_vertex){
1143  // back scattered particle
1144  theta = M_PI - theta;
1145  phi += M_PI;
1146  if(phi<0)phi+=M_TWO_PI;
1147  if(phi>=M_TWO_PI)phi-=M_TWO_PI;
1148  h = -h;
1149  }
1150  tanl=tan(M_PI_2-theta);
1151 
1152  return NOERROR;
1153 }
1154 
1155 //------------------------------------------------------------------
1156 // Print
1157 //------------------------------------------------------------------
1158 jerror_t DHelicalFit::Print(void) const
1159 {
1160  cout<<"-- DHelicalFit Params ---------------"<<endl;
1161  cout<<" x0 = "<<x0<<endl;
1162  cout<<" y0 = "<<y0<<endl;
1163  cout<<" h = "<<h<<endl;
1164  cout<<" phi = "<<phi<<endl;
1165  cout<<" theta = "<<theta<<endl;
1166  cout<<" z_vertex = "<<z_vertex<<endl;
1167  cout<<" chisq = "<<chisq<<endl;
1168  cout<<"chisq_source = ";
1169  switch(chisq_source){
1170  case NOFIT: cout<<"NOFIT"; break;
1171  case CIRCLE: cout<<"CIRCLE"; break;
1172  case TRACK: cout<<"TRACK"; break;
1173  }
1174  cout<<endl;
1175 
1176  return NOERROR;
1177 }
1178 
1179 
1180 //------------------------------------------------------------------
1181 // Dump
1182 //------------------------------------------------------------------
1183 jerror_t DHelicalFit::Dump(void) const
1184 {
1185  Print();
1186 
1187  for(unsigned int i=0;i<hits.size();i++){
1188  DHFHit_t *v = hits[i];
1189  cout<<" x="<<v->x<<" y="<<v->y<<" z="<<v->z;
1190  cout<<" phi_circle="<<v->phi_circle<<" chisq="<<v->chisq<<endl;
1191  }
1192 
1193  return NOERROR;
1194 }
1195 
1196 // Find the sense of the rotation about the circle based on the proximity of
1197 // the hits to the helical trajectory for the two hypotheses
1199  // Try to use a plane with a single hit for the reference position
1200  unsigned int i=1;
1201  for (;i<hits.size()-1;i++){
1202  if (fabs(hits[i-1]->z-hits[i]->z)>0.01
1203  && fabs(hits[i]->z-hits[i+1]->z)>0.01) break;
1204  }
1205 
1206  double Phi1=atan2(hits[i]->y-y0,hits[i]->x-x0);
1207  double z0=hits[i]->z;
1208  double plus_sum=0.,minus_sum=0.;
1209  for (unsigned int j=0;j<hits.size();j++){
1210  DHFHit_t *hit = hits[j];
1211  double dphi=(hit->z-z0)/(r0*tanl);
1212 
1213  double phiplus=Phi1+dphi;
1214  double dxplus=x0+r0*cos(phiplus)-hit->x;
1215  double dyplus=y0+r0*sin(phiplus)-hit->y;
1216  double dxplus2=dxplus*dxplus;
1217  double dyplus2=dyplus*dyplus;
1218  double d2plus=dxplus2+dyplus2;
1219  double varplus=(dxplus2*hit->covx+dyplus2*hit->covy
1220  +2.*dyplus*dxplus*hit->covxy)/d2plus;
1221  plus_sum+=d2plus/varplus;
1222 
1223  double phiminus=Phi1-dphi;
1224  double dxminus=x0+r0*cos(phiminus)-hit->x;
1225  double dyminus=y0+r0*sin(phiminus)-hit->y;
1226  double dxminus2=dxminus*dxminus;
1227  double dyminus2=dyminus*dyminus;
1228  double d2minus=dxminus2+dyminus2;
1229  double varminus=(dxminus2*hit->covx+dyminus2*hit->covy
1230  +2.*dyminus*dxminus*hit->covxy)/d2minus;
1231  minus_sum+=d2minus/varminus;
1232 
1233 
1234  //printf("z %f d+ %f %f d- %f %f\n",hit->z,d2plus,plus_sum,d2minus,minus_sum);
1235 
1236  }
1237 
1238  h=1.0;
1239  // Look for smallest sum to determine q
1240  if (minus_sum<plus_sum) h=-1.;
1241 }
DVector2 xy
rough x,y coordinates in lab coordinate system
Definition: DFDCPseudo.h:100
bool is_axial
Definition: DHelicalFit.h:90
jerror_t Dump(void) const
DHelicalFit(void)
Definition: DHelicalFit.cc:50
jerror_t FitCircleAndLineRiemann(float rc)
Definition: DHelicalFit.cc:983
#define M_TWO_PI
Definition: DHelicalFit.cc:21
TMatrixD DMatrix
Definition: DMatrix.h:14
c Clear()
jerror_t FitTrack(void)
Definition: DHelicalFit.cc:924
double covxx
Definition: DFDCPseudo.h:95
TVector2 DVector2
Definition: DVector2.h:9
float GetZMean() const
Definition: DHelicalFit.h:136
TVector3 DVector3
Definition: DVector3.h:14
Double_t x[NCHANNELS]
Definition: st_tw_resols.C:39
float z_vertex
Definition: DHelicalFit.h:158
#define EPS
Definition: DHelicalFit.cc:19
locHist_ADCmulti Print()
#define c
#define y
bool DHFProjection_cmp(const DHFProjection_t &a, const DHFProjection_t &b)
Definition: DHelicalFit.cc:39
const DFDCWire * wire
DFDCWire for this wire.
Definition: DFDCPseudo.h:92
bool DHFHitLessThanZ_C(DHFHit_t *const &a, DHFHit_t *const &b)
Definition: DHelicalFit.cc:32
#define B0
Definition: src/md5.cpp:23
jerror_t FitCircleRiemann(float rc=0.)
Definition: DHelicalFit.cc:505
class DFDCPseudo: definition for a reconstructed point in the FDC
Definition: DFDCPseudo.h:74
#define SQRT3
Definition: DHelicalFit.cc:18
void SearchPtrans(double ptrans_max=9.0, double ptrans_step=0.5)
Definition: DHelicalFit.cc:829
#define X(str)
Definition: hddm-c.cpp:83
jerror_t AddHitXYZ(float x, float y, float z)
Definition: DHelicalFit.cc:200
jerror_t Print(void) const
float chisq
chi-sq contribution of this hit
Definition: DHelicalFit.h:89
double covrphi
Definition: DHelicalFit.h:86
jerror_t AddHit(float r, float phi, float z)
Definition: DHelicalFit.cc:190
float GetPhiMean() const
Definition: DHelicalFit.h:137
const double alpha
double covy
Definition: DHelicalFit.h:85
jerror_t GuessChargeFromCircleFit(void)
Definition: DHelicalFit.cc:887
int straw
Definition: DCDCWire.h:81
jerror_t Clear(void)
Definition: DHelicalFit.cc:346
DHelicalFit & operator=(const DHelicalFit &fit)
Definition: DHelicalFit.cc:138
jerror_t Fill_phi_circle(vector< DHFHit_t * > hits, float x0, float y0)
ChiSqSourceType_t chisq_source
Definition: DHelicalFit.h:162
#define _DBG_
Definition: HDEVIO.h:12
double covxy
Definition: DFDCPseudo.h:95
double s
&lt; wire position computed from cathode data, assuming the avalanche occurs at the wire ...
Definition: DFDCPseudo.h:91
float dzdphi
Definition: DHelicalFit.h:161
jerror_t FitCircle(void)
Definition: DHelicalFit.cc:385
jerror_t PrintChiSqVector(void) const
Definition: DHelicalFit.cc:358
jerror_t FitLine_FixedZvertex(float z_vertex)
const vector< DHFHit_t * > GetHits() const
Definition: DHelicalFit.h:132
double covyy
Covariance terms for (x,y)
Definition: DFDCPseudo.h:95
jerror_t FitTrackRiemann(float rc)
Definition: DHelicalFit.cc:973
double w
Definition: DFDCPseudo.h:89
jerror_t FitLineRiemann(void)
Definition: DHelicalFit.cc:660
double sqrt(double)
void Reset(void)
Definition: DHelicalFit.cc:73
double sin(double)
double covx
Definition: DHelicalFit.h:85
jerror_t FillTrackParams(void)
float phi_circle
&lt; error info in radial coordinates
Definition: DHelicalFit.h:88
void FindSenseOfRotation(void)
#define S(str)
Definition: hddm-c.cpp:84
jerror_t FitCircleStraightTrack()
Definition: DHelicalFit.cc:762
#define ONE_THIRD
Definition: DHelicalFit.cc:17
bool operator()(DHFHit_t *const &a, DHFHit_t *const &b) const
Definition: DHelicalFit.cc:27
double covxy
error info for x and y coordinates
Definition: DHelicalFit.h:85
jerror_t FitTrack_FixedZvertex(float z_vertex)
Definition: DHelicalFit.cc:997
void Copy(const DHelicalFit &fit)
Definition: DHelicalFit.cc:110
int ring
Definition: DCDCWire.h:80
jerror_t PruneHit(int idx)
Definition: DHelicalFit.cc:330
jerror_t AddStereoHit(const DCDCWire *wire)
Definition: DHelicalFit.cc:258
#define atan2f(x, y)
Definition: DHelicalFit.h:78
float x
Definition: DHelicalFit.h:84
#define BeamRMS
TDirectory * dir
Definition: bcal_hist_eff.C:31
bool RiemannFit_hit_cmp(DHFHit_t *a, DHFHit_t *b)
Definition: DHelicalFit.cc:35
TH2F * temp
union @6::@8 u
float z
point in lab coordinates
Definition: DHelicalFit.h:84
float y
Definition: DHelicalFit.h:84
float stereo
Definition: DCDCWire.h:82
double covr
&lt; error info in RPhi coordinates
Definition: DHelicalFit.h:87
double ChisqCircle(void)
Definition: DHelicalFit.cc:449