Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DTrackFitterRiemann.cc
Go to the documentation of this file.
1 //************************************************************************
2 // DTrackFitterRiemann.cc
3 //************************************************************************
4 // Uses drift time information to refine the results of the circle and line
5 // fits in the Riemann fit formalism.
6 
7 #include "DTrackFitterRiemann.h"
8 #include "START_COUNTER/DSCHit.h"
10 #include "PID/DParticleID.h"
11 #include <TDecompLU.h>
12 #include <math.h>
13 #include <cmath>
14 using namespace std;
15 
16 #define MOLIERE_FRACTION 0.99
17 #define ONE_THIRD 0.33333333333333333
18 #define ONE_SIXTH 0.16666666666666667
19 #define TWO_THIRDS 0.66666666666666667
20 #define EPS 1e-8
21 #define Z_MIN 50.0
22 #define Z_VERTEX 65.0
23 #define Z_MAX 80.0
24 
25 // Variance for position along wire using PHENIX angle dependence, transverse
26 // diffusion, and an intrinsic resolution of 127 microns.
27 #define DIFFUSION_COEFF 1.1e-6 // cm^2/s --> 200 microns at 1 cm
28 #define DRIFT_SPEED .0055
29 #define FDC_CATHODE_VARIANCE 0.02*0.02
30 inline double fdc_y_variance(double my_tanl,double x){
31  double diffusion=2.*DIFFUSION_COEFF*fabs(x)/DRIFT_SPEED;
32  //return FDC_CATHODE_VARIANCE;
33  return diffusion+FDC_CATHODE_VARIANCE+0.0064/my_tanl/my_tanl;
34 }
35 // Smearing function from Yves
36 inline double cdc_variance(double x){
37  // return CDC_VARIANCE;
38 
39  x*=10.; // mm
40  if (x>7.895) x=7.895; // straw radius in mm
41  else if (x<0) x=0.;
42  double sigma_d
43  =(108.55 + 7.62391*x + 556.176*exp(-(1.12566)*pow(x,1.29645)))*1e-4;
44 
45  return sigma_d*sigma_d;
46 }
47 
49 
50 }
51 
53 {
54  // Use the current best knowledge for the track parameters at the "vertex"
55  // to set the seed (initial) values for the fit
56  jerror_t error = SetSeed(input_params.charge(), input_params.position(),
58  if (error!=NOERROR) return kFitFailed;
59 
60  // Clear the hits
61  for (unsigned int i=0;i<my_line_hits.size();i++){
62  if (my_line_hits[i]->fdc==NULL)
63  delete my_line_hits[i];
64  }
65  my_line_hits.clear();
66  for (unsigned int i=0;i<my_circle_hits.size();i++){
67  delete my_circle_hits[i];
68  }
69  my_circle_hits.clear();
70 
71  // Clear the projection and s vectors
72  projections.clear();
73  s.clear();
74 
75  // Deal with cdc axial hits
76  DVector2 XY(-D*sin(phi0),D*cos(phi0)); // Starting radial coords.
77  double sperp=0.; // perpendicular arc length
78  for (unsigned int i=0;i<cdchits.size();i++){
79  // Axial wires
80  if (fabs(cdchits[i]->wire->stereo)<EPS){
81  DRiemannHit_t *hit= new DRiemannHit_t;
82  // Pointers to fdc/cdc hit objects
83  hit->fdc=NULL;
84  hit->cdc=cdchits[i];
85 
86  GetAxialPosition(sperp,XY,hit);
87  XY=hit->XY;
88 
89  my_circle_hits.push_back(hit);
90  }
91  }
92 
93  // Add the FDC hits to the circle hit list
94  for (unsigned int i=0;i<fdchits.size();i++){
95  DRiemannHit_t *hit= new DRiemannHit_t;
96  // Pointers to fdc/cdc hit objects
97  hit->fdc=fdchits[i];
98  hit->cdc=NULL;
99 
100  hit->z=hit->fdc->wire->origin.z();
101  GetFDCPosition(hit);
102 
103  my_circle_hits.push_back(hit);
104  }
105 
106  // Check that we have enough hits on the circle to proceed
107  if (my_circle_hits.size()<3) return kFitFailed;
108 
109  // Otherwise proceed with the fit...
110 
111  // Using the new combined list of hits, compute the covariance matrix
112  // for RPhi associated with these hits
113  unsigned int ncirclehits=my_circle_hits.size();
114  CRPhi.ResizeTo(ncirclehits,ncirclehits);
115  ComputeCRPhi();
116 
117  // Do the circle fit
118  if (FitCircle()!=NOERROR) return kFitFailed;
119 
120  // Deal with cdc stereo hits
121  // .. First compute starting radial coords
122  XY.Set(-D*sin(phi0),D*cos(phi0));
123  sperp=0.; // perpendicular arc length
124  for (unsigned int i=0;i<cdchits.size();i++){
125  // Stereo wires
126  if (fabs(cdchits[i]->wire->stereo)>EPS){
127  DRiemannHit_t *hit= new DRiemannHit_t;
128  // Pointers to fdc/cdc hit objects
129  hit->fdc=NULL;
130  hit->cdc=cdchits[i];
131 
132  GetStereoPosition(sperp,XY,hit);
133 
134  my_line_hits.push_back(hit);
135  }
136  }
137 
138  // Add the fdc hits to the my_line_hits vector
139  for (unsigned int i=0;i<my_circle_hits.size();i++){
140  DRiemannHit_t *hit= my_circle_hits[i];
141  if (hit->fdc!=NULL){
142  GetFDCPosition(hit);
143 
144  my_line_hits.push_back(hit);
145  }
146  }
147 
148  // Check that we have enough hits for the line fit
149  if (my_line_hits.size()<2) return kFitFailed;
150 
151  // If we have enough hits, proceed...
152  unsigned int nhits=my_line_hits.size();
153  projections.resize(nhits);
154  s.resize(nhits);
155 
156  if (ComputeIntersections()!=NOERROR) return kFitFailed;
157 
158  // If there are no fdc hits, then the data needed for the line fit is coming
159  // purely from the stereo wires, for which the relevant error is in z
160  if (fdchits.size()==0){
161  unsigned int nstereo=my_line_hits.size();
162  Cz.ResizeTo(nstereo,nstereo);
163  ComputeCz();
164  }
165  else{
166  // If we have FDC hits, then the relevant error for the line fit is in R:
167  // Size the matrices according to the number of hits
168  CR.ResizeTo(nhits,nhits);
169  ComputeCR();
170  }
171 
172  // Do the line fit
173  FitLine();
174 
175  if (cdchits.size()>0)
176  {
177  // Get the field value
178  B=bfield->GetBz(-D*sin(phi0),D*cos(phi0),z_vertex);
179 
180  // Compute the magnitude of the momentum at this stage of the fit:
181  double cosl=cos(atan(tanl));
182  p=0.003*fabs(B)*rc/cosl;
183  one_over_vcosl=sqrt(1.+mass2/(p*p))/(29.98*cosl);
184 
185  // reset sperp to zero
186  sperp=0.;
187  // Get FDC and CDC axial positions with refined circle and line parameters
188  for (unsigned int i=0;i<my_circle_hits.size();i++){
190  if (hit->fdc!=NULL){
191  GetFDCPosition(hit);
192  }
193  if (hit->cdc!=NULL){
194  GetAxialPosition(sperp,XY,hit);
195  XY=hit->XY;
196  }
197  }
198  // Compute the covariance matrix for RPhi
199  ComputeCRPhi();
200 
201  // Do the circle fit
202  if (FitCircle()!=NOERROR) return kFitFailed;
203 
204  // Recompute the intersections with the circle and redo the line fit,
205  // this time with drift time information for the stereo wires
206  for (unsigned int i=0;i<nhits;i++){
207  DRiemannHit_t *hit=my_line_hits[i];
208  // Use the results of the previous line fit to predict the z-value
209  // for a certain arc length value s and use this to determine the
210  // direction of the correction to the wire position for the drift
211  // time.
212  if (hit->cdc!=NULL){
213  DVector2 XYp=GetHelicalPosition(s[i]);
214  DVector2 dXY(XYp.X()-xc,XYp.Y()-yc);
215  double drw=dXY.Mod();
216  DVector2 dir=(1./drw)*dXY;
217  double d_drift=0.0055*(hit->cdc->tdrift-s[i]*one_over_vcosl)
218  *cos(hit->cdc->wire->stereo);
219 
220  // prediction for z
221  double zpred=z_vertex+s[i]*tanl;
222  DVector2 dXYtest=d_drift*dir;
223  // Two LR solutions
224  double zplus=GetStereoZ(dXYtest.X(),dXYtest.Y(),hit);
225  double zminus=GetStereoZ(-dXYtest.X(),-dXYtest.Y(),hit);
226  if (zpred>=167.3){
227  zpred=167.3;
228  if (zminus<zpred){
229  hit->z=zminus;
230  }
231  else if (zplus<zpred){
232  hit->z=zplus;
233  }
234  else hit->z=zpred;
235  }
236  else if (zpred<=17.){
237  zpred=17.0;
238  if (zminus>zpred){
239  hit->z=zminus;
240  }
241  else if (zplus>zpred){
242  hit->z=zplus;
243  }
244  else hit->z=zpred;
245  }
246  else{
247  if (fabs(zplus-zpred)<fabs(zminus-zpred)){
248  hit->z=zplus;
249  }
250  else{
251  hit->z=zminus;
252  }
253  }
254  // Crude approximation for covariances
255  double var=cdc_variance(d_drift);
256  hit->covx=var*dir.X()*dir.X();
257  hit->covy=var*dir.Y()*dir.Y();
258  hit->covz*=var/0.2133;
259  }
260  else{
261  GetFDCPosition(hit);
262  }
263  }
264  if (ComputeIntersections()!=NOERROR) return kFitFailed;
265 
266  // New covariance matrix for z
267  if (fdchits.size()==0){
268  // New covariance matrix for z
269  ComputeCz();
270  }
271  else{
272  // New covariance matrix for R
273  ComputeCR();
274  }
275 
276  // Do the line fit
277  FitLine();
278  }
279 
280  double sinphi=sin(phi0);
281  double cosphi=cos(phi0);
282  double x0=-D*sinphi;
283  double y0=D*cosphi;
284  if (fit_type==kWireBased){
285  B=bfield->GetBz(x0,y0,z_vertex);
286  }
287  else{
288  B=0;
289  for (unsigned int i=0;i<my_line_hits.size();i++){
290  const DRiemannHit_t *hit=my_line_hits[i];
291  B+=bfield->GetBz(hit->XY.X(),hit->XY.Y(),hit->z);
292  }
293  B/=my_line_hits.size();
294  }
295 
296  double pt=0.003*fabs(B)*rc;
298  fit_params.setMomentum(DVector3(pt*cosphi,pt*sinphi,pt*tanl));
300  this->chisq=ChiSq();
301 
302  return kFitSuccess;
303 }
304 
305 //-----------------
306 // ChiSq
307 //-----------------
308 double DTrackFitterRiemann::ChiSq(fit_type_t fit_type, DReferenceTrajectory *rt, double *chisq_ptr, int *dof_ptr, vector<pull_t> *pulls_ptr)
309 {
310  double chisq = ChiSq();
311  unsigned int ndf = this->Ndof;
312 
313  if(chisq_ptr)*chisq_ptr = chisq;
314  if(dof_ptr)*dof_ptr = int(ndf);
315  //if(pulls_ptr)*pulls_ptr = pulls;
316 
317  printf("reduced chi2 %f\n",chisq/double(ndf));
318  return chisq/double(ndf);
319 
320 
321 }
322 
323 // Compute the chi2 for the fit using both the line and circle hits
325  double chi2=0;
326  this->Ndof=my_circle_hits.size()-5;
327  double sperp=0.;
328  double x0=-D*sin(phi0);
329  double y0=D*cos(phi0);
330  DVector2 XYold(x0,y0);
331  // First take care of the FDC hits and the cdc axial wires
332  for (unsigned int i=0;i<my_circle_hits.size();i++){
333  if (my_circle_hits[i]->fdc!=NULL){
334  sperp=(my_circle_hits[i]->z-z_vertex)/tanl;
335  }
336  else{
337  double ratio=(my_circle_hits[i]->XY-XYold).Mod()/(2.*rc);
338  sperp+=2.*rc*((ratio>1.)?M_PI_2:asin(ratio));
339  XYold=my_circle_hits[i]->XY;
340  }
341  // Position on the fitted helix
342  DVector2 XYp=GetHelicalPosition(sperp);
343 
344  double Phi=my_circle_hits[i]->XY.Phi();
345  double cosPhi=cos(Phi);
346  double sinPhi=sin(Phi);
347  chi2+=(my_circle_hits[i]->XY-XYp).Mod2()
348  /(cosPhi*cosPhi*my_circle_hits[i]->covx
349  +sinPhi*sinPhi*my_circle_hits[i]->covy
350  +2.*sinPhi*cosPhi*my_circle_hits[i]->covxy);
351  }
352 
353  // Next take care of the cdc stereo wires
354  XYold.Set(x0,y0);
355  sperp=0.;
356  for (unsigned int i=0;i<my_line_hits.size();i++){
357  if (my_line_hits[i]->cdc!=NULL){
358  this->Ndof++;
359  //double sperp=(my_line_hits[i]->z-z_vertex)/tanl;
360  double ratio=(my_line_hits[i]->XY-XYold).Mod()/(2.*rc);
361  sperp+=2.*rc*((ratio>1.)?M_PI_2:asin(ratio));
362  XYold=my_line_hits[i]->XY;
363 
364  // Position on the fitted helix
365  DVector2 XYp=GetHelicalPosition(sperp);
366 
367  double Phi=my_line_hits[i]->XY.Phi();
368  double cosPhi=cos(Phi);
369  double sinPhi=sin(Phi);
370  chi2+=(my_line_hits[i]->XY-XYp).Mod2()
371  /(cosPhi*cosPhi*my_line_hits[i]->covx
372  +sinPhi*sinPhi*my_line_hits[i]->covy
373  +2.*sinPhi*cosPhi*my_line_hits[i]->covxy);
374  }
375  }
376 
377  return chi2;
378 }
379 
380 // Initialize the state vector
381 jerror_t DTrackFitterRiemann::SetSeed(double my_q,const DVector3 &pos,
382  const DVector3 &mom,
383  double mass){
384  if (!isfinite(pos.Mag()) || !isfinite(mom.Mag())){
385  _DBG_ << "Invalid seed data." <<endl;
386  return UNRECOVERABLE_ERROR;
387  }
388  // mass squared
389  mass2=mass*mass;
390 
391  // Momentum
392  p=mom.Mag();
393  if (p>8.){
394  p=8.;
395  }
396 
397  // Charge
398  q=my_q;
399 
400  // Dip angle
401  //double lambda=M_PI_2-mom.Theta();;
402  //tanl=tan(lambda);
403  theta=mom.Theta();
404  tanl=tan(M_PI_2-theta);
405 
406  one_over_vcosl=sqrt(1.+mass2/(p*p))/(29.98*sin(theta));
407 
408  // Phi angle
409  phi0=mom.Phi();
410 
411  // "vertex" position along z
412  z_vertex=pos.z();
413 
414  // Circle parameters
415  B=bfield->GetBz(pos.x(),pos.y(),pos.z());
416  if (fit_type==kTimeBased){
417  if (fdchits.size()>0){
418  for (unsigned int i=0;i<fdchits.size();i++){
419  const DFDCPseudo *hit=fdchits[i];
420  double u=hit->w;
421  double v=hit->s;
422  double cosa=hit->wire->udir.y();
423  double sina=hit->wire->udir.x();
424  B+=bfield->GetBz(u*cosa+v*sina,-u*sina+v*cosa,hit->wire->origin.z());
425  }
426  B/=fdchits.size()+1;
427  }
428  }
429 
430  rc=p*sin(theta)/fabs(0.003*B);
431  xc=pos.x()-q*rc*sin(phi0);
432  yc=pos.y()+q*rc*cos(phi0);
433  // Signed distance to origin
434  D=-pos.x()/sin(phi0);
435 
436  return NOERROR;
437 }
438 
439 // Correct the axial wire positions with the drift distance
441  const DVector2 &XYold,
442  DRiemannHit_t *hit){
443  DVector2 XY(hit->cdc->wire->origin.x(),hit->cdc->wire->origin.y());
444  DVector2 dXY(XY.X()-xc,XY.Y()-yc);
445  double drw=dXY.Mod();
446  DVector2 dir=(1./drw)*dXY;
447 
448  double sign=(drw<rc)?1.:-1.;
449  double ratio=(XY-XYold).Mod()/(2.*rc);
450  sperp+=2.*rc*((ratio>1.)?M_PI_2:asin(ratio));
451  double tflight=sperp*one_over_vcosl;
452  double d_drift=0.0055*(hit->cdc->tdrift-tflight);
453  hit->XY=XY+sign*d_drift*dir;
454 
455  // Crude approximation for covariance matrix ignoring error in dir
456  double var=cdc_variance(d_drift);
457  hit->covx=var*dir.X()*dir.X();
458  hit->covy=var*dir.Y()*dir.Y();
459  hit->covxy=0.;
460 
461  return NOERROR;
462 }
463 
464 // Get the z-position of the intersection between the cylinder of radius rc
465 // and the stereo wire
466 double DTrackFitterRiemann::GetStereoZ(double dx,double dy,
467  DRiemannHit_t *hit){
468  double uz=hit->cdc->wire->udir.z();
469  double ux=hit->cdc->wire->udir.x()/uz;
470  double uy=hit->cdc->wire->udir.y()/uz;
471  double denom=ux*ux+uy*uy;
472 
473  // wire origin
474  double dxwire0=xc-(hit->cdc->wire->origin.x()+dx);
475  double dywire0=yc-(hit->cdc->wire->origin.y()+dy);
476  double zwire0=hit->cdc->wire->origin.z();
477  // Compute the z position
478  double my_z=zwire0+(dxwire0*ux+dywire0*uy)/denom;
479  double temp=uy*dxwire0-ux*dywire0;
480  double rootz2=denom*rc*rc-temp*temp;
481  if (rootz2>0.){
482  double rootz=sqrt(rootz2)/denom;
483  double z1=my_z+rootz;
484  double z2=my_z-rootz;
485 
486  if (fabs(z2-Z_VERTEX)>fabs(z1-Z_VERTEX)){
487  my_z=z1;
488  }
489  else{
490  my_z=z2;
491  }
492  }
493  //if (my_z>167.3) my_z=167.3;
494  //if (my_z<17.0) my_z=17.0;
495 
496  return my_z;
497 }
498 
499 // Get the position of the intersection between the cylinder of radius rc
500 // and the stereo wire
502  DVector2 &XYold,
503  DRiemannHit_t *hit){
504  double uz=hit->cdc->wire->udir.z();
505  double ux=hit->cdc->wire->udir.x()/uz;
506  double uy=hit->cdc->wire->udir.y()/uz;
507  double denom=ux*ux+uy*uy;
508 
509  // wire origin
510  double dxwire0=xc-hit->cdc->wire->origin.x();
511  double dywire0=yc-hit->cdc->wire->origin.y();
512  double zwire0=hit->cdc->wire->origin.z();
513  hit->z=zwire0+(dxwire0*ux+dywire0*uy)/denom;
514  double temp=uy*dxwire0-ux*dywire0;
515  double rootz2=denom*rc*rc-temp*temp;
516  double dx0dz=ux/denom;
517  double dy0dz=uy/denom;
518  if (rootz2>0.){
519  double rootz=sqrt(rootz2)/denom;
520  double z1=hit->z+rootz;
521  double z2=hit->z-rootz;
522 
523  double temp1=temp/(rootz*denom*denom);
524  if (fabs(z2-Z_VERTEX)>fabs(z1-Z_VERTEX)){
525  hit->z=z1;
526  //dx0dz+=((uy*(xwire0-xc)-ux*(ywire0-yc))*uy/rootz)/denom;
527  //dy0dz-=((uy*(xwire0-xc)-ux*(ywire0-yc))*ux/rootz)/denom;
528  dx0dz+=temp1*uy;
529  dy0dz-=temp1*ux;
530  }
531  else{
532  hit->z=z2;
533  //dx0dz-=((uy*(xwire0-xc)-ux*(ywire0-yc))*uy/rootz)/denom;
534  //dy0dz+=((uy*(xwire0-xc)-ux*(ywire0-yc))*ux/rootz)/denom;
535  dx0dz-=temp1*uy;
536  dy0dz+=temp1*ux;
537  }
538  }
539  // Deal with endplates
540  if (hit->z>167.3) hit->z=167.3;
541  if (hit->z<17.0) hit->z=17.0;
542  double dzwire=hit->z-zwire0;
543  hit->XY.Set(hit->cdc->wire->origin.x()+ux*dzwire,
544  hit->cdc->wire->origin.y()+uy*dzwire);
545 
546  DVector2 dXY(hit->XY.X()-xc,hit->XY.Y()-yc);
547  double drw=dXY.Mod();
548  DVector2 dir=(1./drw)*dXY;
549  // Crude approximation for covariance matrix ignoring error in dir
550  hit->covx=0.2133*dir.X()*dir.X();
551  hit->covy=0.2133*dir.Y()*dir.Y();
552  hit->covxy=0.;
553  hit->covz=dx0dz*dx0dz*hit->covx+dy0dz*dy0dz*hit->covy;
554 
555  XYold=hit->XY;
556 
557  return NOERROR;
558 }
559 
560 // Compute the position on the helical trajectory for a given arc length
562  double twokappa=q/rc;
563  double twoks=twokappa*sperp;
564  double sin2ks=sin(twoks);
565  double cos2ks=cos(twoks);
566  double cosphi=cos(phi0);
567  double sinphi=sin(phi0);
568  double one_minus_cos2ks=1.-cos2ks;
569  double one_over_2k=1./(twokappa);
570  return
571  DVector2(-D*sinphi+(cosphi*sin2ks-sinphi*one_minus_cos2ks)*one_over_2k,
572  D*cosphi+(sinphi*sin2ks+cosphi*one_minus_cos2ks)*one_over_2k);
573 }
574 
575 
576 // Compute the position from the FDC hit, correcting for the drift time and
577 // the Lorentz effect
579  // Position on the helical trajectory
580  hit->z=hit->fdc->wire->origin.z();
581  double sperp=(hit->z-z_vertex)/tanl;
582  //double my_phi=phi1+q*sperp/rc;
583  //double x=xc+rc*cos(my_phi);
584  //double y=yc+rc*sin(my_phi);
585  DVector2 XYp=GetHelicalPosition(sperp);
586 
587  // Find difference between point on helical path and wire
588  double cosa=hit->fdc->wire->udir.y();
589  double sina=hit->fdc->wire->udir.x();
590  //double w=x*cosa-y*sina-hit->fdc->w;
591  double w=XYp.X()*cosa-XYp.Y()*sina-hit->fdc->w;
592  // .. and use it to determine which sign to use for the drift time data
593  double sign=(w>0?1.:-1.);
594 
595  // Correct the drift time for the flight path and convert to distance
596  // units
597  double delta_x=sign*(hit->fdc->time-sperp*one_over_vcosl)*55E-4;
598 
599  // Next find correction to y from table of deflections
600  double delta_y=0.;
601 
602  double u=hit->fdc->w+delta_x;
603  double v=hit->fdc->s-delta_y;
604  hit->XY.Set(u*cosa+v*sina,-u*sina+v*cosa);
605 
606  // Measurement covariance
607  double cosa2=cosa*cosa;
608  double sina2=sina*sina;
609  double sigx2=0.0004;
610  double sigy2=fdc_y_variance(tanl,delta_x);
611  hit->covx=sigx2*cosa2+sigy2*sina2;
612  hit->covy=sigx2*sina2+sigy2*cosa2;
613  hit->covxy=(sigy2-sigx2)*sina*cosa;
614 
615 
616  return NOERROR;
617 }
618 
619 // Compute the error matrices for the RPhi coordinates
621  // Size the matrices according to the number of hits
622  unsigned int nhits=my_circle_hits.size();
623  DMatrix my_CR(nhits,nhits);// Needed for correction for non-normal incidence
624 
625  // Zero the CRPhi matrix out before filling them with new data
626  CRPhi.Zero();
627 
628  // Loop over the hits, fill in diagonal elements
629  for (unsigned int i=0;i<nhits;i++){
630  double Phi=my_circle_hits[i]->XY.Phi();
631  double cosPhi=cos(Phi);
632  double sinPhi=sin(Phi);
633  double Phi_sinPhi_plus_cosPhi=Phi*sinPhi+cosPhi;
634  double Phi_cosPhi_minus_sinPhi=Phi*cosPhi-sinPhi;
635  CRPhi(i,i)=Phi_cosPhi_minus_sinPhi*Phi_cosPhi_minus_sinPhi*my_circle_hits[i]->covx
636  +Phi_sinPhi_plus_cosPhi*Phi_sinPhi_plus_cosPhi*my_circle_hits[i]->covy
637  +2.*Phi_sinPhi_plus_cosPhi*Phi_cosPhi_minus_sinPhi*my_circle_hits[i]->covxy;
638  my_CR(i,i)=cosPhi*cosPhi*my_circle_hits[i]->covx+sinPhi*sinPhi*my_circle_hits[i]->covy
639  +2.*sinPhi*cosPhi*my_circle_hits[i]->covxy;
640  }
641  //printf("Errors\n");
642  //my_CR.Print();
643  //CRPhi.Print();
644 
645  // Correct the covariance matrices for contributions due to multiple
646  // scattering
647  DMatrix CRPhi_ms(nhits,nhits);
648  double lambda=atan(tanl);
649  double cosl=cos(lambda);
650  if (cosl<EPS) cosl=EPS;
651  double cosl2=cosl*cosl;
652  for (unsigned int m=0;m<nhits;m++){
653  double Rm=my_circle_hits[m]->XY.Mod();
654  for (unsigned int k=m;k<nhits;k++){
655  double Rk=my_circle_hits[k]->XY.Mod();
656  unsigned int imax=(k>m)?m:k;
657  for (unsigned int i=0;i<imax;i++){
658  double zi=my_circle_hits[i]->z;
659  double sigma2_ms=GetProcessNoise(my_circle_hits[i]->XY,zi);
660  if (std::isnan(sigma2_ms)){
661  sigma2_ms=0.;
662  }
663  double Ri=my_circle_hits[i]->XY.Mod();
664  CRPhi_ms(m,k)+=sigma2_ms*(Rk-Ri)*(Rm-Ri)/cosl2;
665  }
666  CRPhi_ms(k,m)=CRPhi_ms(m,k);
667  }
668  }
669  CRPhi+=CRPhi_ms;
670 
671  // Correction for non-normal incidence of track at the intersection R=R_i
672  // The correction is
673  // CRPhi'= C*CRPhi*C+S*CR*S, where S(i,i)=R_i*kappa/2
674  // and C(i,i)=sqrt(1-S(i,i)^2)
675  DMatrix C(nhits,nhits);
676  DMatrix S(nhits,nhits);
677  for (unsigned int i=0;i<my_circle_hits.size();i++){
678  double stemp=my_circle_hits[i]->XY.Mod()/(4.*rc);
679  double ctemp=1.-stemp*stemp;
680  if (ctemp>0){
681  S(i,i)=stemp;
682  C(i,i)=sqrt(ctemp);
683  }
684  else{
685  S(i,i)=0.;
686  C(i,i)=1;
687  }
688  }
689  CRPhi=C*CRPhi*C+S*my_CR*S;
690  /*
691  CR.Print();
692  CRPhi.Print();
693  */
694  return NOERROR;
695 }
696 
697 // Compute the error matrix for the R coordinates
699  unsigned int nhits=my_line_hits.size();
700 
701  // Zero out the matrix before filling with new elements
702  CR.Zero();
703 
704  // Loop over the hits, fill in diagonal elements
705  for (unsigned int i=0;i<nhits;i++){
706  double Phi=my_line_hits[i]->XY.Phi();
707  double cosPhi=cos(Phi);
708  double sinPhi=sin(Phi);
709  CR(i,i)=cosPhi*cosPhi*my_line_hits[i]->covx+sinPhi*sinPhi*my_line_hits[i]->covy
710  +2.*sinPhi*cosPhi*my_line_hits[i]->covxy;
711  }
712  // printf("Errors\n");
713  //CR.Print();
714  //CRPhi.Print();
715 
716  // Correct the covariance matrix for contributions due to multiple
717  // scattering
718  DMatrix CR_ms(nhits,nhits);
719  double lambda=atan(tanl);
720  double sinl=sin(lambda);
721  if (sinl<EPS) sinl=EPS;
722  double sinl4=sinl*sinl*sinl*sinl;
723  for (unsigned int m=0;m<nhits;m++){
724  double zm=my_line_hits[m]->z;
725  for (unsigned int k=m;k<nhits;k++){
726  double zk=my_line_hits[k]->z;
727  unsigned int imax=(k>m)?m:k;
728  for (unsigned int i=0;i<imax;i++){
729  double zi=my_line_hits[i]->z;
730  double sigma2_ms=GetProcessNoise(my_line_hits[i]->XY,zi);
731  if (std::isnan(sigma2_ms)){
732  sigma2_ms=0.;
733  }
734  CR_ms(m,k)+=sigma2_ms*(zk-zi)*(zm-zi)/sinl4;
735  }
736  CR_ms(k,m)=CR_ms(m,k);
737  }
738  }
739  CR+=CR_ms;
740  /*
741  CR.Print();
742  CRPhi.Print();
743  */
744  return NOERROR;
745 }
746 
747 // Compute the covariance matrix for z
749  unsigned int n=my_line_hits.size();
750  // First zero out the matrix
751  Cz.Zero();
752 
753  // Next deal with the diagonal components
754  for (unsigned int i=0;i<n;i++){
755  Cz(i,i)=my_line_hits[i]->covz;
756  }
757  // Correct the Cz covariance matrix for contributions due to multiple
758  // scattering
759  DMatrix Cz_ms(n,n);
760  double lambda=atan(tanl);
761  double cosl=cos(lambda);
762  if (cosl<EPS) cosl=EPS;
763  double cosl4=cosl*cosl*cosl*cosl;
764  for (unsigned int m=0;m<n;m++){
765  for (unsigned int k=m;k<n;k++){
766  unsigned int imax=(k>m)?m:k;
767  for (unsigned int i=0;i<imax;i++){
768  double zi=my_line_hits[k]->z;
769  double sigma2_ms=GetProcessNoise(my_line_hits[i]->XY,zi);
770  if (std::isnan(sigma2_ms)){
771  sigma2_ms=0.;
772  }
773  Cz_ms(m,k)+=sigma2_ms*(s[k]-s[i])*(s[m]-s[i])/cosl4;
774  }
775  Cz_ms(k,m)=Cz_ms(m,k);
776  }
777  }
778  Cz+=Cz_ms;
779 
780  return NOERROR;
781 }
782 
783 // Compute the variance of the projected multiple scattering angle following
784 // the formalism of Lynch and Dahl
785 double DTrackFitterRiemann::GetProcessNoise(const DVector2 &XY,const double z){
786  // Get the material properties for this position
787  double rho_Z_over_A,K_rho_Z_over_A,LnI,Z;
788  double chi2c_factor,chi2a_factor,chi2a_corr;
789  DVector3 pos(XY.X(),XY.Y(),z);
790  unsigned int dummy=0;
791  if(geom->FindMatKalman(pos,K_rho_Z_over_A,rho_Z_over_A,LnI,Z,
792  chi2c_factor,chi2a_factor,chi2a_corr,
793  dummy)!=NOERROR){
794  return 0.;
795  }
796 
797  double p2=p*p;
798  double F=MOLIERE_FRACTION; // Fraction of Moliere distribution to be taken into account
799  double one_over_beta2=1.+mass2/p2;
800  double my_ds=1.;
801  double chi2c=chi2c_factor*my_ds*one_over_beta2/p2;
802  double chi2a=chi2a_factor*(1.+chi2a_corr*one_over_beta2)/p2;
803  double nu=0.5*chi2c/(chi2a*(1.-F));
804  return (2.*chi2c*1e-6/(1.+F*F)*((1.+nu)/nu*log(1.+nu)-1.));
805 }
806 
807 
808 //-----------------
809 // FitCircle
810 //-----------------
812 /// Riemann Circle fit: points on a circle in x,y project onto a plane cutting
813 /// the circular paraboloid surface described by (x,y,x^2+y^2). Therefore the
814 /// task of fitting points in (x,y) to a circle is transormed to the task of
815 /// fitting planes in (x,y, w=x^2+y^2) space
816 ///
817  unsigned nhits=my_circle_hits.size();
818  DMatrix X(nhits,3);
819  DMatrix Xavg(1,3);
820  DMatrix A(3,3);
821  double B0,B1,B2,Q,Q1,R,sum,diff;
822  double angle,lambda_min=0.;
823  // Column and row vectors of ones
824  DMatrix Ones(nhits,1),OnesT(1,nhits);
825  DMatrix W_sum(1,1);
826  DMatrix W(nhits,nhits);
827 
828  // The goal is to find the eigenvector corresponding to the smallest
829  // eigenvalue of the equation
830  // lambda=n^T (X^T W X - W_sum Xavg^T Xavg)n
831  // where n is the normal vector to the plane slicing the cylindrical
832  // paraboloid described by the parameterization (x,y,w=x^2+y^2),
833  // and W is the weight matrix, assumed for now to be diagonal.
834  // In the absence of multiple scattering, W_sum is the sum of all the
835  // diagonal elements in W.
836 
837  for (unsigned int i=0;i<nhits;i++){
838  X(i,0)=my_circle_hits[i]->XY.X();
839  X(i,1)=my_circle_hits[i]->XY.Y();
840  X(i,2)=my_circle_hits[i]->XY.Mod2();
841  Ones(i,0)=OnesT(0,i)=1.;
842  }
843 
844  // Check that CRPhi is invertible
845  TDecompLU lu(CRPhi);
846  if (lu.Decompose()==false){
847  return UNRECOVERABLE_ERROR; // error placeholder
848  }
849  W=DMatrix(DMatrix::kInverted,CRPhi);
850  W_sum=OnesT*(W*Ones);
851  Xavg=(1./W_sum(0,0))*(OnesT*(W*X));
852 
853  A=DMatrix(DMatrix::kTransposed,X)*(W*X)
854  -W_sum(0,0)*(DMatrix(DMatrix::kTransposed,Xavg)*Xavg);
855  if(!A.IsValid()){
856  return UNRECOVERABLE_ERROR;
857  }
858 
859  // The characteristic equation is
860  // lambda^3+B2*lambda^2+lambda*B1+B0=0
861  //
862  B2=-(A(0,0)+A(1,1)+A(2,2));
863  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)+A(1,1)*A(2,2)
864  -A(2,1)*A(1,2);
865  B0=-A.Determinant();
866  if(B0==0 || !isfinite(B0)){
867  return UNRECOVERABLE_ERROR;
868  }
869 
870  // The roots of the cubic equation are given by
871  // lambda1= -B2/3 + S+T
872  // lambda2= -B2/3 - (S+T)/2 + i sqrt(3)/2. (S-T)
873  // lambda3= -B2/3 - (S+T)/2 - i sqrt(3)/2. (S-T)
874  // where we define some temporary variables:
875  // S= (R+sqrt(Q^3+R^2))^(1/3)
876  // T= (R-sqrt(Q^3+R^2))^(1/3)
877  // Q=(3*B1-B2^2)/9
878  // R=(9*B2*B1-27*B0-2*B2^3)/54
879  // sum=S+T;
880  // diff=i*(S-T)
881  // We divide Q and R by a safety factor to prevent multiplying together
882  // enormous numbers that cause unreliable results.
883 
884  Q=(3.*B1-B2*B2)/9.e4;
885  R=(9.*B2*B1-27.*B0-2.*B2*B2*B2)/54.e6;
886  Q1=Q*Q*Q+R*R;
887  if (Q1<EPS){
888  if (fabs(Q1)<EPS) Q1=0.;
889  else Q1=sqrt(-Q1);
890  // DeMoivre's theorem for fractional powers of complex numbers:
891  // (r*(cos(angle)+i sin(angle)))^(p/q)
892  // = r^(p/q)*(cos(p*angle/q)+i sin(p*angle/q))
893  //
894  double temp=100.*pow(R*R+Q1*Q1,0.16666666666666666667);
895  angle=atan2(Q1,R)/3.;
896  sum=2.*temp*cos(angle);
897  diff=-2.*temp*sin(angle);
898  // Third root
899  lambda_min=-B2/3.-sum/2.+sqrt(3.)/2.*diff;
900  }
901  else{
902  Q1=sqrt(Q1);
903  // first root
904  lambda_min=-B2/3+pow(R+Q1,ONE_THIRD)+pow(R-Q1,ONE_THIRD);
905  }
906 
907  // Calculate the (normal) eigenvector corresponding to the eigenvalue lambda
908  N.SetXYZ(1.,
909  (A(1,0)*A(0,2)-(A(0,0)-lambda_min)*A(1,2))
910  /(A(0,1)*A(2,1)-(A(1,1)-lambda_min)*A(0,2)),
911  (A(2,0)*(A(1,1)-lambda_min)-A(1,0)*A(2,1))
912  /(A(1,2)*A(2,1)-(A(2,2)-lambda_min)*(A(1,1)-lambda_min)));
913 
914  // Normalize: n1^2+n2^2+n3^2=1
915  N.SetMag(1.0);
916 
917  // Distance to origin
918  c_origin=-(N.X()*Xavg(0,0)+N.Y()*Xavg(0,1)+N.Z()*Xavg(0,2));
919 
920  // Center and radius of the circle
921  double one_over_2Nz=1./(2.*N.Z());
922  xc=-N.X()*one_over_2Nz;
923  yc=-N.Y()*one_over_2Nz;
924  rc=sqrt(1.-N.Z()*N.Z()-4.*c_origin*N.Z())*fabs(one_over_2Nz);
925 
926  // Phi value at "vertex"
927  phi0=atan2(-xc,yc);
928  if (q<0) phi0+=M_PI;
929  if(phi0<0)phi0+=2.0*M_PI;
930  if(phi0>=2.0*M_PI)phi0-=2.0*M_PI;
931 
932  D=yc/cos(phi0)-q*rc;
933 
934  // Calculate the chisq
935  //ChisqCircle();
936  //chisq_source = CIRCLE;
937 
938  return NOERROR;
939 }
940 
941 // Compute the intersections of the fitted circle with the measurements
942 // through the paraboloid transform, such that the problem becomes the
943 // calculation of the intersection of two planes -- i.e., a straight line.
944 // Store the cumulative arc length from measurement to measurement.
946  double x_int0,temp,y_int0;
947  double denom=N.Perp();
948  for (unsigned int m=0;m<my_line_hits.size();m++){
949  if (my_line_hits[m]->cdc!=NULL){
950  projections[m]=my_line_hits[m]->XY;
951  }
952  else{
953  double r2=my_line_hits[m]->XY.Mod2();
954  double numer=c_origin+r2*N.z();
955  double ratio=numer/denom;
956  x_int0=-N.x()*ratio;
957  y_int0=-N.y()*ratio;
958 
959  temp=denom*r2-numer*numer;
960  // Since we will be taking a square root next, check for positive value
961  if (temp<0){
962  // Not sure what to do here. Maybe use measurement itself??
963  //projections[m]=DVector2(x_int0,y_int0);
964  projections[m]=my_line_hits[m]->XY;
965 
966  continue;
967  }
968  temp=sqrt(temp)/denom;
969 
970  // Choose sign of square root based on proximity to actual measurements
971  double deltax=N.y()*temp;
972  double deltay=-N.x()*temp;
973  DVector2 XY1(x_int0+deltax,y_int0+deltay);
974  DVector2 XY2(x_int0-deltax,y_int0-deltay);
975  if ((XY1-my_line_hits[m]->XY).Mod2() > (XY2-my_line_hits[m]->XY).Mod2()){
976  projections[m]=XY2;
977  }
978  else{
979  projections[m]=XY1;
980  }
981  }
982  }
983 
984  // Fill in vector of arc lengths
985  double my_s=0;
986  DVector2 XYold(-D*sin(phi0),D*cos(phi0));
987  for (unsigned int m=0;m<my_line_hits.size();m++){
988  double chord_ratio=(projections[m]-XYold).Mod()/(2.*rc);
989  my_s=my_s+(chord_ratio>1.?2.*rc*M_PI_2:2.*rc*asin(chord_ratio));
990  s[m]=my_s;
991  XYold=projections[m];
992  }
993 
994  return NOERROR;
995 }
996 
997 
998 //-----------------
999 // FitLine
1000 //-----------------
1002 /// Riemann Line fit: linear regression to determine the tangent of
1003 /// the dip angle and the z position of the closest approach to the beam line.
1004  // Also computes the average B value over the hits.
1005  unsigned int n=projections.size();
1006  double sumv=0.,sumx=0.,sumy=0.,sumxx=0.,sumxy=0.;
1007  double Delta;
1008  double z=0.;
1009 
1010  DVector2 old_projection=projections[0];
1011  if (fdchits.size()==0){
1012  for (unsigned int k=0;k<n;k++){
1013  z=my_line_hits[k]->z;
1014 
1015  double weight=1./Cz(k,k);
1016  sumv+=weight;
1017  sumy+=z*weight;
1018  sumx+=s[k]*weight;
1019  sumxx+=s[k]*s[k]*weight;
1020  sumxy+=s[k]*z*weight;
1021  }
1022 
1023  Delta=(sumv*sumxx-sumx*sumx);
1024  // Track parameters tan(lambda) and z-vertex
1025  //theta=atan(Delta/(sumv*sumxy-sumy*sumx));
1026  //tanl=tan(M_PI_2-theta);
1027  tanl=(sumv*sumxy-sumx*sumy)/Delta;
1028  theta=M_PI_2-atan(tanl);
1029  z_vertex=(sumxx*sumy-sumx*sumxy)/Delta;
1030 
1031  // Try to constrain the particle to come from somewhere near the center
1032  // of the target if the initial fit result goes out of range in z
1033  if (z_vertex<Z_MIN || z_vertex>Z_MAX){
1034  double weight=1000.;
1035  sumv+=weight;
1036  sumy+=Z_VERTEX*weight;
1037  Delta= sumv*sumxx-sumx*sumx;
1038  tanl=(sumv*sumxy-sumx*sumy)/Delta;
1039  theta=M_PI_2-atan(tanl);
1040  z_vertex=(sumxx*sumy-sumx*sumxy)/Delta;
1041  }
1042  }
1043  else{ // Got FDC hits
1044  for (unsigned int k=0;k<n;k++){
1045  z=my_line_hits[k]->z;
1046 
1047  // Assume errors in s dominated by errors in R
1048  double weight=1./CR(k,k);
1049  sumv+=weight;
1050  sumy+=s[k]*weight;
1051  sumx+=z*weight;
1052  sumxx+=z*z*weight;
1053  sumxy+=s[k]*z*weight;
1054  }
1055 
1056  Delta= sumv*sumxx-sumx*sumx;
1057  double Delta1=sumv*sumxy-sumy*sumx;
1058  // Track parameters tan(lambda) and z-vertex
1059  tanl=Delta/Delta1;
1060  theta=M_PI_2-atan(tanl);
1061 
1062  z_vertex=-(sumxx*sumy-sumx*sumxy)/Delta1;
1063 
1064  // Try to constrain the particle to come from somewhere near the center
1065  // of the target if the initial fit result goes out of range in z
1066  if (z_vertex<Z_MIN || z_vertex>Z_MAX){
1067  double weight=1000.;
1068  sumv+=weight;
1069  sumx+=Z_VERTEX*weight;
1070  sumxx+=Z_VERTEX*Z_VERTEX*weight;
1071  Delta= sumv*sumxx-sumx*sumx;
1072  Delta1=sumv*sumxy-sumy*sumx;
1073  // Track parameters tan(lambda) and z-vertex
1074  tanl=Delta/Delta1;
1075  theta=M_PI_2-atan(tanl);
1076  z_vertex=-(sumxx*sumy-sumx*sumxy)/Delta1;
1077  }
1078 
1079  //z_vertex=z-s[n-1]*tanl;
1080  }
1081 
1082  return NOERROR;
1083 }
1084 
1085 
1086 
1088 
1089 
1090  return NOERROR;
1091 }
#define FDC_CATHODE_VARIANCE
#define F(x, y, z)
void setMomentum(const DVector3 &aMomentum)
double GetProcessNoise(const DVector2 &XY, const double z)
double z
point in lab coordinates
Definition: DRiemannFit.h:12
#define DRIFT_SPEED
TMatrixD DMatrix
Definition: DMatrix.h:14
jerror_t GetStereoPosition(double &sperp, DVector2 &XYold, DRiemannHit_t *hit)
const DCDCWire * wire
Definition: DCDCTrackHit.h:37
#define MOLIERE_FRACTION
The DTrackFitter class is a base class for different charged track fitting algorithms. It does not actually fit the track itself, but provides the interface and some common support features most algorthims will need to implement.
Definition: DTrackFitter.h:61
TVector2 DVector2
Definition: DVector2.h:9
TVector3 DVector3
Definition: DVector3.h:14
Double_t x[NCHANNELS]
Definition: st_tw_resols.C:39
fit_type_t fit_type
Definition: DTrackFitter.h:227
const DVector3 & position(void) const
const DFDCWire * wire
DFDCWire for this wire.
Definition: DFDCPseudo.h:92
vector< DRiemannHit_t * > my_line_hits
fit_status_t FitTrack(void)
#define B0
Definition: src/md5.cpp:23
class DFDCPseudo: definition for a reconstructed point in the FDC
Definition: DFDCPseudo.h:74
#define X(str)
Definition: hddm-c.cpp:83
#define DIFFUSION_COEFF
jerror_t SetSeed(double my_q, const DVector3 &pos, const DVector3 &mom, double mass)
const DMagneticFieldMap * bfield
Definition: DTrackFitter.h:228
TEllipse * e
vector< const DCDCTrackHit * > cdchits
Definition: DTrackFitter.h:224
double cdc_variance(double x)
const DGeometry * geom
Definition: DTrackFitter.h:229
double fdc_y_variance(double my_tanl, double x)
#define ONE_THIRD
DTrackFitterRiemann(JEventLoop *loop)
const DFDCPseudo * fdc
jerror_t GetAxialPosition(double &sperp, const DVector2 &XYold, DRiemannHit_t *hit)
#define _DBG_
Definition: HDEVIO.h:12
double s
&lt; wire position computed from cathode data, assuming the avalanche occurs at the wire ...
Definition: DFDCPseudo.h:91
#define EPS
double charge(void) const
double covxy
error info for x and y coordinates
Definition: DRiemannFit.h:13
const DCDCTrackHit * cdc
double w
Definition: DFDCPseudo.h:89
double time
time corresponding to this pseudopoint.
Definition: DFDCPseudo.h:93
void setPID(Particle_t locPID)
vector< DRiemannHit_t * > my_circle_hits
double sqrt(double)
virtual double GetBz(double x, double y, double z) const =0
vector< const DFDCPseudo * > fdchits
Definition: DTrackFitter.h:225
double sin(double)
#define S(str)
Definition: hddm-c.cpp:84
const DVector3 & momentum(void) const
DTrackingData input_params
Definition: DTrackFitter.h:226
vector< DVector2 > projections
jerror_t GetFDCPosition(DRiemannHit_t *hit)
#define Z_VERTEX
jerror_t FindMatKalman(const DVector3 &pos, const DVector3 &mom, double &KrhoZ_overA, double &rhoZ_overA, double &LnI, double &Z, double &chi2c_factor, double &chi2a_factor, double &chi2a_factor2, unsigned int &last_index, double *s_to_boundary=NULL) const
Definition: DGeometry.cc:254
double GetStereoZ(double dx, double dy, DRiemannHit_t *hit)
DVector2 GetHelicalPosition(double sperp)
void setPosition(const DVector3 &aPosition)
TDirectory * dir
Definition: bcal_hist_eff.C:31
static Particle_t IDTrack(float locCharge, float locMass)
DTrackingData fit_params
Definition: DTrackFitter.h:234
printf("string=%s", string)
TH2F * temp
union @6::@8 u
#define Z_MAX
float stereo
Definition: DCDCWire.h:82
double mass(void) const