Bug Summary

File:libraries/FDC/DFDCSegment_factory.cc
Location:line 504, column 5
Description:Value stored to 'error' is never read

Annotated Source Code

1//************************************************************************
2// DFDCSegment_factory.cc - factory producing track segments from pseudopoints
3//************************************************************************
4
5#include "DFDCSegment_factory.h"
6#include "DANA/DApplication.h"
7//#include "HDGEOMETRY/DLorentzMapCalibDB.h"
8#include <math.h>
9#include <cmath>
10using namespace std;
11
12// some of these aren't being used anymore, so I've commented them out - sdobbs, 6/3/14
13//#define HALF_CELL 0.5
14//#define MAX_DEFLECTION 0.15
15#define EPS1e-8 1e-8
16//#define KILL_RADIUS 5.0
17#define MATCH_RADIUS2.0 2.0
18#define ADJACENT_MATCH_DISTANCE0.3 0.3
19//#define SIGN_CHANGE_CHISQ_CUT 10.0
20//#define USED_IN_SEGMENT 0x8
21//#define CORRECTED 0x10
22//#define MAX_ITER 10
23//#define MIN_TANL 2.0
24#define ONE_THIRD0.33333333333333333 0.33333333333333333
25#define SQRT31.73205080756887719 1.73205080756887719
26
27
28
29// Variance for position along wire using PHENIX angle dependence, transverse
30// diffusion, and an intrinsic resolution of 127 microns.
31// Deprecated!
32//inline double fdc_y_variance(double alpha,double x){
33// return 0.00060+0.0064*tan(alpha)*tan(alpha)+0.0004*fabs(x);
34//}
35
36bool DFDCSegment_package_cmp(const DFDCPseudo* a, const DFDCPseudo* b) {
37 return a->wire->layer>b->wire->layer;
38}
39
40DFDCSegment_factory::DFDCSegment_factory() {
41 _log = new JStreamLog(std::cout, "FDCSEGMENT >>");
42 *_log << "File initialized." << endMsg;
43}
44
45
46///
47/// DFDCSegment_factory::~DFDCSegment_factory():
48/// default destructor -- closes log file
49///
50DFDCSegment_factory::~DFDCSegment_factory() {
51 delete _log;
52}
53///
54/// DFDCSegment_factory::brun():
55/// Initialization: read in deflection map, get magnetic field map
56///
57jerror_t DFDCSegment_factory::brun(JEventLoop* eventLoop, int runnumber) {
58 DApplication* dapp=dynamic_cast<DApplication*>(eventLoop->GetJApplication());
59 const DMagneticFieldMap *bfield = dapp->GetBfield(runnumber);
60 double Bz=bfield->GetBz(0.,0.,65.);
61 RotationSenseToCharge=(Bz>0.)?-1.:1.;
62
63 // get the geometry
64 const DGeometry *geom = dapp->GetDGeometry(runnumber);
65
66 geom->GetTargetZ(TARGET_Z);
67 /*
68 bfield = dapp->GetBfield();
69 lorentz_def=dapp->GetLorentzDeflections();
70
71 *_log << "Table of Lorentz deflections initialized." << endMsg;
72 */
73 DEBUG_LEVEL=0;
74 gPARMS->SetDefaultParameter("FDC:DEBUG_LEVEL", DEBUG_LEVEL);
75
76 BEAM_VARIANCE=1.0;
77 gPARMS->SetDefaultParameter("FDC:BEAM_VARIANCE",BEAM_VARIANCE);
78
79
80 return NOERROR;
81}
82
83///
84/// DFDCSegment_factory::evnt():
85/// Routine where pseudopoints are combined into track segments
86///
87jerror_t DFDCSegment_factory::evnt(JEventLoop* eventLoop, int eventNo) {
88 myeventno=eventNo;
89
90 vector<const DFDCPseudo*>pseudopoints;
91 eventLoop->Get(pseudopoints);
92
93 // Skip segment finding if there aren't enough points to form a sensible
94 // segment
95 if (pseudopoints.size()>=3){
96 // Group pseudopoints by package
97 vector<const DFDCPseudo*>package[4];
98 for (vector<const DFDCPseudo*>::const_iterator i=pseudopoints.begin();
99 i!=pseudopoints.end();i++){
100 package[((*i)->wire->layer-1)/6].push_back(*i);
101 }
102
103 // Find the segments in each package
104 for (int j=0;j<4;j++){
105 std::sort(package[j].begin(),package[j].end(),DFDCSegment_package_cmp);
106 // We need at least 3 points to define a circle, so skip if we don't
107 // have enough points.
108 if (package[j].size()>2) FindSegments(package[j]);
109 }
110 } // pseudopoints>2
111
112 return NOERROR;
113}
114
115// Riemann Line fit: linear regression of s on z to determine the tangent of
116// the dip angle and the z position of the closest approach to the beam line.
117// Also returns predicted positions along the helical path.
118//
119jerror_t DFDCSegment_factory::RiemannLineFit(vector<const DFDCPseudo *>points,
120 DMatrix &CR,vector<xyz_t>&XYZ){
121 unsigned int n=points.size()+1;
122 vector<int>bad(n); // Keep track of "bad" intersection points
123 bool got_bad_intersection=false;
124 // Fill matrix of intersection points
125 for (unsigned int m=0;m<n-1;m++){
126 double r2=points[m]->xy.Mod2();
127 double denom= N[0]*N[0]+N[1]*N[1];
128 double numer=dist_to_origin+r2*N[2];
129 double ratio=numer/denom;
130
131 DVector2 xy_int0(-N[0]*ratio,-N[1]*ratio);
132 double temp=denom*r2-numer*numer;
133 if (temp<0){
134 got_bad_intersection=true;
135 bad[m]=1;
136 XYZ[m].xy=points[m]->xy;
137 continue;
138 }
139 temp=sqrt(temp)/denom;
140
141 // Choose sign of square root based on proximity to actual measurements
142 DVector2 delta(N[1]*temp,-N[0]*temp);
143 DVector2 xy1=xy_int0+delta;
144 DVector2 xy2=xy_int0-delta;
145 double diff1=(xy1-points[m]->xy).Mod2();
146 double diff2=(xy2-points[m]->xy).Mod2();
147 if (diff1>diff2){
148 XYZ[m].xy=xy2;
149 }
150 else{
151 XYZ[m].xy=xy1;
152 }
153 }
154 // Fake target point
155 XYZ[n-1].xy.Set(0.,0.);
156
157 // Linear regression to find z0, tanl
158 double sumv=0.,sumx=0.;
159 double sumy=0.,sumxx=0.,sumxy=0.;
160 double sperp=0.,sperp_old=0.,ratio,Delta;
161 double z=0,zlast=0;
162 double two_rc=2.*rc;
163 DVector2 oldxy=XYZ[0].xy;
164 for (unsigned int k=0;k<n;k++){
165 zlast=z;
166 z=XYZ[k].z;
167 if (fabs(z-zlast)<0.01) continue;
168
169 DVector2 diffxy=XYZ[k].xy-oldxy;
170 double var=CR(k,k);
171 if (bad[k]) var=XYZ[k].covr;
172
173 sperp_old=sperp;
174 ratio=diffxy.Mod()/(two_rc);
175 // Make sure the argument for the arcsin does not go out of range...
176 sperp=sperp_old+(ratio>1?two_rc*(M_PI_21.57079632679489661923):two_rc*asin(ratio));
177 //z=XYZ(k,2);
178
179 // Assume errors in s dominated by errors in R
180 double inv_var=1./var;
181 sumv+=inv_var;
182 sumy+=sperp*inv_var;
183 sumx+=z*inv_var;
184 sumxx+=z*z*inv_var;
185 sumxy+=sperp*z*inv_var;
186
187 // Save the current x and y coordinates
188 //oldx=XYZ(k,0);
189 //oldy=XYZ(k,1);
190 oldxy=XYZ[k].xy;
191 }
192
193 Delta=sumv*sumxx-sumx*sumx;
194 double denom=sumv*sumxy-sumy*sumx;
195 if (fabs(Delta)>EPS1e-8 && fabs(denom)>EPS1e-8){
196 // Track parameters z0 and tan(lambda)
197 tanl=-Delta/denom;
198 //z0=(sumxx*sumy-sumx*sumxy)/Delta*tanl;
199 // Error in tanl
200 var_tanl=sumv/Delta*(tanl*tanl*tanl*tanl);
201
202 // Vertex position
203 sperp-=sperp_old;
204 zvertex=zlast-tanl*sperp;
205 }
206 else{
207 // assume that the particle came from the target
208 zvertex=TARGET_Z;
209 if (sperp<EPS1e-8){
210 // This is a rare failure mode where it seems that the arc length data
211 // cannot be reliably used. Provide some default value of tanl to
212 // avoid division by zero errors
213 tanl=57.3; // theta=1 degree
214 }
215 else tanl=(zlast-zvertex)/sperp;
216 var_tanl=100.; // guess for now
217 }
218 if (got_bad_intersection) return VALUE_OUT_OF_RANGE;
219 return NOERROR;
220}
221
222// Use predicted positions (propagating from plane 1 using a helical model) to
223// update the R and RPhi covariance matrices.
224//
225jerror_t DFDCSegment_factory::UpdatePositionsAndCovariance(unsigned int n,
226 double r1sq,vector<xyz_t>&XYZ,DMatrix &CRPhi,DMatrix &CR){
227 double delta_x=XYZ[ref_plane].xy.X()-xc;
228 double delta_y=XYZ[ref_plane].xy.Y()-yc;
229 double r1=sqrt(r1sq);
230 double denom=delta_x*delta_x+delta_y*delta_y;
231
232 // Auxiliary matrices for correcting for non-normal track incidence to FDC
233 // The correction is
234 // CRPhi'= C*CRPhi*C+S*CR*S, where S(i,i)=R_i*kappa/2
235 // and C(i,i)=sqrt(1-S(i,i)^2)
236 DMatrix C(n,n);
237 DMatrix S(n,n);
238
239 // Predicted positions
240 Phi1=atan2(delta_y,delta_x);
241 double z1=XYZ[ref_plane].z;
242 double y1=XYZ[ref_plane].xy.X();
243 double x1=XYZ[ref_plane].xy.Y();
244 double var_R1=CR(ref_plane,ref_plane);
245 for (unsigned int k=0;k<n;k++){
246 double sperp=rotation_sense*(XYZ[k].z-z1)/tanl;
247 double phi_s=Phi1+sperp/rc;
248 double sinp=sin(phi_s);
249 double cosp=cos(phi_s);
250 XYZ[k].xy.Set(xc+rc*cosp,yc+rc*sinp);
251
252 // Error analysis. We ignore errors in N because there doesn't seem to
253 // be any obvious established way to estimate errors in eigenvalues for
254 // small eigenvectors. We assume that most of the error comes from
255 // the measurement for the reference plane radius and the dip angle anyway.
256 double Phi=XYZ[k].xy.Phi();
257 double sinPhi=sin(Phi);
258 double cosPhi=cos(Phi);
259 double dRPhi_dx=Phi*cosPhi-sinPhi;
260 double dRPhi_dy=Phi*sinPhi+cosPhi;
261
262 double rc_sinphi_over_denom=rc*sinp/denom;
263 //double dx_dx1=rc*sinp*delta_y/denom;
264 //double dx_dy1=-rc*sinp*delta_x/denom;
265 double dx_dx1=rc_sinphi_over_denom*delta_y;
266 double dx_dy1=-rc_sinphi_over_denom*delta_x;
267 double dx_dtanl=sinp*sperp/tanl;
268
269 double rc_cosphi_over_denom=rc*cosp/denom;
270 //double dy_dx1=-rc*cosp*delta_y/denom;
271 //double dy_dy1=rc*cosp*delta_x/denom;
272 double dy_dx1=-rc_cosphi_over_denom*delta_y;
273 double dy_dy1=rc_cosphi_over_denom*delta_x;
274 double dy_dtanl=-cosp*sperp/tanl;
275
276 double dRPhi_dx1=dRPhi_dx*dx_dx1+dRPhi_dy*dy_dx1;
277 double dRPhi_dy1=dRPhi_dx*dx_dy1+dRPhi_dy*dy_dy1;
278 double dRPhi_dtanl=dRPhi_dx*dx_dtanl+dRPhi_dy*dy_dtanl;
279
280 double dR_dx1=cosPhi*dx_dx1+sinPhi*dy_dx1;
281 double dR_dy1=cosPhi*dx_dy1+sinPhi*dy_dy1;
282 double dR_dtanl=cosPhi*dx_dtanl+sinPhi*dy_dtanl;
283
284 double cdist=dist_to_origin+r1sq*N[2];
285 double n2=N[0]*N[0]+N[1]*N[1];
286
287 double ydenom=y1*n2+N[1]*cdist;
288 double dy1_dr1=-r1*(2.*N[1]*N[2]*y1+2.*N[2]*cdist-N[0]*N[0])/ydenom;
289 double var_y1=dy1_dr1*dy1_dr1*var_R1;
290
291 double xdenom=x1*n2+N[0]*cdist;
292 double dx1_dr1=-r1*(2.*N[0]*N[2]*x1+2.*N[2]*cdist-N[1]*N[1])/xdenom;
293 double var_x1=dx1_dr1*dx1_dr1*var_R1;
294
295 CRPhi(k,k)=dRPhi_dx1*dRPhi_dx1*var_x1+dRPhi_dy1*dRPhi_dy1*var_y1
296 +dRPhi_dtanl*dRPhi_dtanl*var_tanl;
297 CR(k,k)=dR_dx1*dR_dx1*var_x1+dR_dy1*dR_dy1*var_y1
298 +dR_dtanl*dR_dtanl*var_tanl;
299
300 // double stemp=sqrt(XYZ(k,0)*XYZ(k,0)+XYZ(k,1)*XYZ(k,1))/(4.*rc);
301 double stemp=XYZ[k].xy.Mod()/(4.*rc);
302 double ctemp=1.-stemp*stemp;
303 if (ctemp>0){
304 S(k,k)=stemp;
305 C(k,k)=sqrt(ctemp);
306 }
307 else{
308 S(k,k)=0.;
309 C(k,k)=1.;
310 }
311 }
312
313 // Correction for non-normal incidence of track on FDC
314 CRPhi=C*CRPhi*C+S*CR*S;
315
316 return NOERROR;
317}
318
319// Riemann Circle fit: points on a circle in x,y project onto a plane cutting
320// the circular paraboloid surface described by (x,y,x^2+y^2). Therefore the
321// task of fitting points in (x,y) to a circle is transormed to the taks of
322// fitting planes in (x,y, w=x^2+y^2) space
323//
324jerror_t DFDCSegment_factory::RiemannCircleFit(vector<const DFDCPseudo *>points,
325 DMatrix &CRPhi){
326 unsigned int n=points.size()+1;
327 DMatrix X(n,3);
328 DMatrix Xavg(1,3);
329 DMatrix A(3,3);
330 // vector of ones
331 DMatrix OnesT(1,n);
332 double W_sum=0.;
333 DMatrix W(n,n);
334
335 // The goal is to find the eigenvector corresponding to the smallest
336 // eigenvalue of the equation
337 // lambda=n^T (X^T W X - W_sum Xavg^T Xavg)n
338 // where n is the normal vector to the plane slicing the cylindrical
339 // paraboloid described by the parameterization (x,y,w=x^2+y^2),
340 // and W is the weight matrix, assumed for now to be diagonal.
341 // In the absence of multiple scattering, W_sum is the sum of all the
342 // diagonal elements in W.
343 // At this stage we ignore the multiple scattering.
344 unsigned int last_index=n-1;
345 for (unsigned int i=0;i<last_index;i++){
346 X(i,0)=points[i]->xy.X();
347 X(i,1)=points[i]->xy.Y();
348 X(i,2)=points[i]->xy.Mod2();
349 OnesT(0,i)=1.;
350 W(i,i)=1./CRPhi(i,i);
351 W_sum+=W(i,i);
352 }
353 OnesT(0,last_index)=1.;
354 W(last_index,last_index)=1./CRPhi(last_index,last_index);
355 W_sum+=W(last_index,last_index);
356 var_avg=1./W_sum;
357 Xavg=var_avg*(OnesT*(W*X));
358 // Store in private array for use in other routines
359 xavg[0]=Xavg(0,0);
360 xavg[1]=Xavg(0,1);
361 xavg[2]=Xavg(0,2);
362
363 A=DMatrix(DMatrix::kTransposed,X)*(W*X)
364 -W_sum*(DMatrix(DMatrix::kTransposed,Xavg)*Xavg);
365 if(!A.IsValid())return UNRECOVERABLE_ERROR;
366
367 // The characteristic equation is
368 // lambda^3+B2*lambda^2+lambda*B1+B0=0
369 //
370 double B2=-(A(0,0)+A(1,1)+A(2,2));
371 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)
372 +A(1,1)*A(2,2)-A(2,1)*A(1,2);
373 double B0=-A.Determinant();
374 if(B0==0 || !isfinite(B0))return UNRECOVERABLE_ERROR;
375
376 // The roots of the cubic equation are given by
377 // lambda1= -B2/3 + S+T
378 // lambda2= -B2/3 - (S+T)/2 + i sqrt(3)/2. (S-T)
379 // lambda3= -B2/3 - (S+T)/2 - i sqrt(3)/2. (S-T)
380 // where we define some temporary variables:
381 // S= (R+sqrt(Q^3+R^2))^(1/3)
382 // T= (R-sqrt(Q^3+R^2))^(1/3)
383 // Q=(3*B1-B2^2)/9
384 // R=(9*B2*B1-27*B0-2*B2^3)/54
385 // sum=S+T;
386 // diff=i*(S-T)
387 // We divide Q and R by a safety factor to prevent multiplying together
388 // enormous numbers that cause unreliable results.
389
390 double Q=(3.*B1-B2*B2)/9.e4;
391 double R=(9.*B2*B1-27.*B0-2.*B2*B2*B2)/54.e6;
392 double Q1=Q*Q*Q+R*R;
393 if (Q1<0) Q1=sqrt(-Q1);
394 else{
395 return VALUE_OUT_OF_RANGE;
396 }
397
398 // DeMoivre's theorem for fractional powers of complex numbers:
399 // (r*(cos(theta)+i sin(theta)))^(p/q)
400 // = r^(p/q)*(cos(p*theta/q)+i sin(p*theta/q))
401 //
402 //double temp=100.*pow(R*R+Q1*Q1,0.16666666666666666667);
403 double temp=100.*sqrt(cbrt(R*R+Q1*Q1));
404 double theta1=ONE_THIRD0.33333333333333333*atan2(Q1,R);
405 double sum_over_2=temp*cos(theta1);
406 double diff_over_2=-temp*sin(theta1);
407 // Third root
408 double lambda_min=-ONE_THIRD0.33333333333333333*B2-sum_over_2+SQRT31.73205080756887719*diff_over_2;
409
410 // Normal vector to plane
411 N[0]=1.;
412 double A11_minus_lambda_min=A(1,1)-lambda_min;
413 N[1]=(A(1,0)*A(0,2)-(A(0,0)-lambda_min)*A(1,2))
414 /(A(0,1)*A(2,1)-(A11_minus_lambda_min)*A(0,2));
415 N[2]=(A(2,0)*A11_minus_lambda_min-A(1,0)*A(2,1))
416 /(A(1,2)*A(2,1)-(A(2,2)-lambda_min)*A11_minus_lambda_min);
417
418 // Normalize: n1^2+n2^2+n3^2=1
419 double denom=sqrt(N[0]*N[0]+N[1]*N[1]+N[2]*N[2]);
420 for (int i=0;i<3;i++){
421 N[i]/=denom;
422 }
423
424 // Distance to origin
425 dist_to_origin=-(N[0]*Xavg(0,0)+N[1]*Xavg(0,1)+N[2]*Xavg(0,2));
426
427 // Center and radius of the circle
428 double two_N2=2.*N[2];
429 xc=-N[0]/two_N2;
430 yc=-N[1]/two_N2;
431 rc=sqrt(1.-N[2]*N[2]-4.*dist_to_origin*N[2])/fabs(two_N2);
432
433 return NOERROR;
434}
435
436// Riemann Helical Fit based on transforming points on projection to x-y plane
437// to a circular paraboloid surface combined with a linear fit of the arc
438// length versus z. Uses RiemannCircleFit and RiemannLineFit.
439//
440jerror_t DFDCSegment_factory::RiemannHelicalFit(vector<const DFDCPseudo*>points,
441 DMatrix &CR,vector<xyz_t>&XYZ){
442 double Phi;
443 unsigned int num_measured=points.size();
444 unsigned int last_index=num_measured;
445 unsigned int num_points=num_measured+1;
446 DMatrix CRPhi(num_points,num_points);
447
448 // Fill initial matrices for R and RPhi measurements
449 for (unsigned int m=0;m<num_measured;m++){
450 XYZ[m].z=points[m]->wire->origin.z();
451
452 //Phi=atan2(points[m]->y,points[m]->x);
453 Phi=points[m]->xy.Phi();
454
455 double u=points[m]->w;
456 double v=points[m]->s;
457 double temp1=u*Phi-v;
458 double temp2=v*Phi+u;
459 double var_u=0.08333;
460 double var_v=0.0075;
461 double one_over_R2=1./points[m]->xy.Mod2();
462 CRPhi(m,m)=one_over_R2*(var_v*temp1*temp1+var_u*temp2*temp2);
463 CR(m,m)=one_over_R2*(var_u*u*u+var_v*v*v);
464
465 XYZ[m].covr=CR(m,m);
466 XYZ[m].covrphi=CRPhi(m,m);
467 }
468 XYZ[last_index].z=TARGET_Z;
469 CR(last_index,last_index)=BEAM_VARIANCE;
470 CRPhi(last_index,last_index)=BEAM_VARIANCE;
471
472 // Reference track:
473 jerror_t error=NOERROR;
474 // First find the center and radius of the projected circle
475 error=RiemannCircleFit(points,CRPhi);
476 if (error!=NOERROR){
477 if (DEBUG_LEVEL>0) _DBG_std::cerr<<"libraries/FDC/DFDCSegment_factory.cc"<<
":"<<477<<" "
<< "Circle fit failed..." << endl;
478 return error;
479 }
480
481 // Get reference track estimates for z0 and tanl and intersection points
482 // (stored in XYZ)
483 error=RiemannLineFit(points,CR,XYZ);
484 if (error!=NOERROR){
485 // The circle fit is inconsistent with at least one of the measured points
486 // (i.e., the calcuation of the intersection point failed). Relax the
487 // emphasis on the "target" point and refit.
488 for (unsigned int i=0;i<last_index;i++){
489 CR(i,i)=XYZ[i].covr;
490 CRPhi(i,i)=XYZ[i].covrphi;
491 }
492 CRPhi(last_index,last_index)=100.;
493 CR(last_index,last_index)=100.;
494
495 // First find the center and radius of the projected circle
496 error=RiemannCircleFit(points,CRPhi);
497 if (error!=NOERROR){
498 if (DEBUG_LEVEL>0) _DBG_std::cerr<<"libraries/FDC/DFDCSegment_factory.cc"<<
":"<<498<<" "
<< "Circle fit failed..." << endl;
499 return error;
500 }
501
502 // Get reference track estimates for z0 and tanl and intersection points
503 // (stored in XYZ)
504 error=RiemannLineFit(points,CR,XYZ);
Value stored to 'error' is never read
505 }
506
507 // Guess particle sense of rotation (+/-1);
508 rotation_sense=GetRotationSense(points.size(),XYZ,CR,CRPhi);
509
510 double r1sq=XYZ[ref_plane].xy.Mod2();
511 UpdatePositionsAndCovariance(num_points,r1sq,XYZ,CRPhi,CR);
512
513 // Compute the chi-square value for this iteration
514 double chisq0=0.;
515 double rc0=rc,xc0=xc,yc0=yc,tanl0=tanl,zvertex0=zvertex,Phi1_0=Phi1;
516 double rotation_sense0=rotation_sense;
517 for (unsigned int m=0;m<points.size();m++){
518 double sperp=rotation_sense*(XYZ[m].z-XYZ[ref_plane].z)/tanl;
519 double phi_s=Phi1+sperp/rc;
520 DVector2 XY(xc+rc*cos(phi_s),yc+rc*sin(phi_s));
521 chisq0+=(XY-points[m]->xy).Mod2()/CR(m,m);
522 }
523
524 // Preliminary circle fit
525 error=RiemannCircleFit(points,CRPhi);
526 if (error!=NOERROR){
527 if (DEBUG_LEVEL>0) _DBG_std::cerr<<"libraries/FDC/DFDCSegment_factory.cc"<<
":"<<527<<" "
<< "Circle fit failed..." << endl;
528 return error;
529 }
530
531 // Preliminary line fit
532 error=RiemannLineFit(points,CR,XYZ);
533
534 // Guess particle sense of rotation (+/-1);
535 rotation_sense=GetRotationSense(points.size(),XYZ,CR,CRPhi);
536
537 r1sq=XYZ[ref_plane].xy.Mod2();
538 UpdatePositionsAndCovariance(num_points,r1sq,XYZ,CRPhi,CR);
539
540 // Compute the chi-square value for this iteration
541 double chisq_=0.;
542 double rotation_sense_=rotation_sense;
543 double rc_=rc,xc_=xc,yc_=yc,tanl_=tanl,zvertex_=zvertex,Phi1_=Phi1;
544 for (unsigned int m=0;m<points.size();m++){
545 double sperp=rotation_sense*(XYZ[m].z-XYZ[ref_plane].z)/tanl;
546 double phi_s=Phi1+sperp/rc;
547 DVector2 XY(xc+rc*cos(phi_s),yc+rc*sin(phi_s));
548 chisq_+=(XY-points[m]->xy).Mod2()/CR(m,m);
549 }
550 // If we did not improve the fit, bail from this routine...
551 if (chisq_>chisq0){
552 chisq=chisq0;
553 rotation_sense=rotation_sense0;
554 rc=rc0,xc=xc0,yc=yc0,tanl=tanl0,zvertex=zvertex0,Phi1=Phi1_0;
555
556 return NOERROR;
557 }
558
559 // Final circle fit
560 error=RiemannCircleFit(points,CRPhi);
561 if (error!=NOERROR){
562 if (DEBUG_LEVEL>0) _DBG_std::cerr<<"libraries/FDC/DFDCSegment_factory.cc"<<
":"<<562<<" "
<< "Circle fit failed..." << endl;
563 return error;
564 }
565
566 // Final line fit
567 error=RiemannLineFit(points,CR,XYZ);
568
569 // Guess particle sense of rotation (+/-1)
570 rotation_sense=GetRotationSense(num_measured,XYZ,CR,CRPhi);
571
572 // Final update to covariance matrices
573 r1sq=XYZ[ref_plane].xy.Mod2();
574 UpdatePositionsAndCovariance(num_points,r1sq,XYZ,CRPhi,CR);
575
576 // Store residuals and path length for each measurement
577 chisq=0.;
578 for (unsigned int m=0;m<num_points;m++){
579 double sperp=rotation_sense*(XYZ[m].z-XYZ[ref_plane].z)/tanl;
580 double phi_s=Phi1+sperp/rc;
581 DVector2 XY(xc+rc*cos(phi_s),yc+rc*sin(phi_s));
582
583 if (m<num_measured){
584 chisq+=(XY-points[m]->xy).Mod2()/CR(m,m);
585 }
586 else{
587 chisq+=XY.Mod2()/CR(m,m);
588 }
589 }
590
591 // If the last iteration did not improve the results, restore the previously
592 // saved values for the parameters and chi-square.
593 if (chisq>chisq_){
594 chisq=chisq_;
595 rotation_sense=rotation_sense_;
596 rc=rc_,xc=xc_,yc=yc_,tanl=tanl_,zvertex=zvertex_,Phi1=Phi1_;
597 }
598 Ndof=num_points-3;
599
600 return NOERROR;
601}
602
603
604// DFDCSegment_factory::FindSegments
605// Associate nearest neighbors within a package with track segment candidates.
606// Provide guess for (seed) track parameters
607//
608jerror_t DFDCSegment_factory::FindSegments(vector<const DFDCPseudo*>points){
609 // Clear all the "used" flags;
610 used.clear();
611
612 // Put indices for the first point in each plane before the most downstream
613 // plane in the vector x_list.
614 double old_z=points[0]->wire->origin.z();
615 vector<unsigned int>x_list;
616 x_list.push_back(0);
617 for (unsigned int i=0;i<points.size();i++){
618 used.push_back(false);
619 if (points[i]->wire->origin.z()!=old_z){
620 x_list.push_back(i);
621 }
622 old_z=points[i]->wire->origin.z();
623 }
624 x_list.push_back(points.size());
625
626 unsigned int start=0;
627 // loop over the start indices, starting with the first plane
628 while (start<x_list.size()-1){
629 int num_used=0;
630 // For each iteration, count how many hits we have used already in segments
631 for (unsigned int i=0;i<points.size();i++){
632 if(used[i]==true) num_used++;
633 }
634 // Break out of loop if we don't have enough hits left to fit a circle
635 if (points.size()-num_used<3) break;
636
637 // Now loop over the list of track segment start points
638 for (unsigned int i=x_list[start];i<x_list[start+1];i++){
639 if (used[i]==false){
640 used[i]=true;
641 chisq=1.e8;
642
643 // Clear track parameters
644 tanl=D=z0=phi0=Phi1=xc=yc=rc=0.;
645 rotation_sense=1.;
646
647 // Point in the current plane in the package
648 DVector2 XY=points[i]->xy;
649
650 // Create list of nearest neighbors
651 vector<const DFDCPseudo*>neighbors;
652 neighbors.push_back(points[i]);
653 unsigned int match=0;
654 double delta,delta_min=1000.;
655 for (unsigned int k=0;k<x_list.size()-1;k++){
656 delta_min=1000.;
657 match=0;
658 if (x_list[k]>0){
659 for (unsigned int m=x_list[k];m<x_list[k+1];m++){
660 delta=(XY-points[m]->xy).Mod();
661 if (delta<delta_min && delta<MATCH_RADIUS2.0){
662 delta_min=delta;
663 match=m;
664 }
665 }
666 }
667 if (match!=0
668 && used[match]==false
669 ){
670 XY=points[match]->xy;
671 used[match]=true;
672 neighbors.push_back(points[match]);
673 }
674 }
675 unsigned int num_neighbors=neighbors.size();
676
677 // Skip to next segment seed if we don't have enough points to fit a
678 // circle
679 if (num_neighbors<3) continue;
680
681 bool do_sort=false;
682 // Look for hits adjacent to the ones we have in our segment candidate
683 for (unsigned int k=0;k<points.size();k++){
684 if (!used[k]){
685 for (unsigned int j=0;j<num_neighbors;j++){
686 delta=fabs(points[k]->xy.Y()-neighbors[j]->xy.Y());
687
688 if (delta<ADJACENT_MATCH_DISTANCE0.3 &&
689 abs(neighbors[j]->wire->wire-points[k]->wire->wire)<=1
690 && neighbors[j]->wire->origin.z()==points[k]->wire->origin.z()){
691 used[k]=true;
692 neighbors.push_back(points[k]);
693 do_sort=true;
694 }
695 }
696 }
697 }
698 // Sort if we added another point
699 if (do_sort)
700 std::sort(neighbors.begin(),neighbors.end(),DFDCSegment_package_cmp);
701
702 // list of points on track and the corresponding covariances
703 unsigned int num_points_on_segment=neighbors.size()+1;
704 vector<xyz_t>XYZ(num_points_on_segment);
705 DMatrix CR(num_points_on_segment,num_points_on_segment);
706
707 // Arc lengths in helical model are referenced relative to the plane
708 // ref_plane within a segment. For a 6 hit segment, ref_plane=2 is
709 // roughly in the center of the segment.
710 ref_plane=0;
711
712 // Perform the Riemann Helical Fit on the track segment
713 jerror_t error=RiemannHelicalFit(neighbors,CR,XYZ); /// initial hit-based fit
714
715 if (error==NOERROR){
716 double charge=RotationSenseToCharge*rotation_sense;
717
718 // Since the cell size is 0.5 cm and the Lorentz deflection can be
719 // mm scale, a circle radius on the order of 1 cm is at the level of
720 // how well the points are defined at this stage. Use a simple circle
721 // fit assuming the circle goes through the origin.
722 if (rc<1.0) {
723 CircleFit(neighbors);
724
725 // Linear regression to find z0, tanl
726 double sumv=0.,sumx=0.;
727 double sumy=0.,sumxx=0.,sumxy=0.;
728 double sperp=0.,sperp_old=0.,ratio,Delta;
729 double z=0,zlast=0;
730 double two_rc=2.*rc;
731 DVector2 oldxy=points[0]->xy;
732 for (unsigned int k=1;k<points.size();k++){
733 zlast=z;
734 z=points[k]->wire->origin.z();
735 if (fabs(z-zlast)<0.01) continue;
736
737 DVector2 diffxy=points[k]->xy-oldxy;
738 double Phi=points[k]->xy.Phi();
739 double cosPhi=cos(Phi);
740 double sinPhi=sin(Phi);
741 double var=cosPhi*cosPhi*points[k]->covxx
742 +sinPhi*sinPhi*points[k]->covyy
743 +2.*sinPhi*cosPhi*points[k]->covxy;
744
745 sperp_old=sperp;
746 ratio=diffxy.Mod()/(two_rc);
747 // Make sure the argument for the arcsin does not go out of range...
748 sperp=sperp_old+(ratio>1?two_rc*(M_PI_21.57079632679489661923):two_rc*asin(ratio));
749
750 // Assume errors in s dominated by errors in R
751 double inv_var=1./var;
752 sumv+=inv_var;
753 sumy+=sperp*inv_var;
754 sumx+=z*inv_var;
755 sumxx+=z*z*inv_var;
756 sumxy+=sperp*z*inv_var;
757
758 // Save the current x and y coordinates
759 //oldx=XYZ(k,0);
760 //oldy=XYZ(k,1);
761 oldxy=points[k]->xy;
762 }
763 // last point is at "vertex" --> give it a large error...
764 sperp+=oldxy.Mod()/two_rc;
765 double inv_var=0.01;
766 sumv+=inv_var;
767 sumy+=sperp*inv_var;
768 sumx+=TARGET_Z*inv_var;
769 sumxx+=TARGET_Z*TARGET_Z*inv_var;
770 sumxy+=sperp*TARGET_Z*inv_var;
771
772 Delta=sumv*sumxx-sumx*sumx;
773 double denom=sumv*sumxy-sumy*sumx;
774 if (fabs(Delta)>EPS1e-8 && fabs(denom)>EPS1e-8){
775 // Track parameters z0 and tan(lambda)
776 tanl=-Delta/denom;
777 // Vertex position
778 sperp-=sperp_old;
779 zvertex=zlast-tanl*sperp;
780 }
781 }
782
783 // Estimate for azimuthal angle
784 phi0=atan2(-xc,yc);
785 if (rotation_sense<0) phi0+=M_PI3.14159265358979323846;
786 // if (rotation_sense<0) phi0+=M_PI;
787
788 // Look for distance of closest approach nearest to target
789 D=-rotation_sense*rc-xc/sin(phi0);
790
791 // Creat a new segment
792 DFDCSegment *segment = new DFDCSegment;
793
794 // Initialize seed track parameters
795 segment->q=charge; //charge
796 segment->phi0=phi0; // Phi
797 segment->D=D; // D=distance of closest approach to origin
798 segment->tanl=tanl; // tan(lambda), lambda=dip angle
799 segment->z_vertex=zvertex;// z-position at closest approach to origin
800
801 segment->hits=neighbors;
802 segment->xc=xc;
803 segment->yc=yc;
804 segment->rc=rc;
805 segment->Phi1=Phi1;
806 segment->chisq=chisq;
807 segment->Ndof=Ndof;
808 segment->package=(neighbors[0]->wire->layer-1)/6;
809 //printf("tanl %f \n",tanl);
810 //printf("xc %f yc %f rc %f\n",xc,yc,rc);
811
812 _data.push_back(segment);
813 }
814 }
815 }
816 // Move on to the next plane to start looking for segments
817 start++;
818 } //while loop over x_list planes
819
820 return NOERROR;
821}
822
823// Linear regression to find charge
824double DFDCSegment_factory::GetRotationSense(unsigned int n,vector<xyz_t>&XYZ,
825 DMatrix &CR,
826 DMatrix &CRPhi){
827 double inv_var=0.;
828 double sumv=0.;
829 double sumy=0.;
830 double sumx=0.;
831 double sumxx=0.,sumxy=0,Delta;
832 double slope,r2;
833 double phi_old=XYZ[0].xy.Phi();
834 for (unsigned int k=0;k<n;k++){
835 double tempz=XYZ[k].z;
836 double phi_z=XYZ[k].xy.Phi();
837 // Check for problem regions near +pi and -pi
838 if (fabs(phi_z-phi_old)>M_PI3.14159265358979323846){
839 if (phi_old<0) phi_z-=2.*M_PI3.14159265358979323846;
840 else phi_z+=2.*M_PI3.14159265358979323846;
841 }
842 r2=XYZ[k].xy.Mod2();
843 inv_var=r2/(CRPhi(k,k)+phi_z*phi_z*CR(k,k));
844 sumv+=inv_var;
845 sumy+=phi_z*inv_var;
846 sumx+=tempz*inv_var;
847 sumxx+=tempz*tempz*inv_var;
848 sumxy+=phi_z*tempz*inv_var;
849 phi_old=phi_z;
850 }
851 Delta=sumv*sumxx-sumx*sumx;
852 slope=(sumv*sumxy-sumy*sumx)/Delta;
853
854 if (slope<0.) return -1.;
855 return 1.;
856}
857
858// Simple least squares circle fit forcing the circle to go through (0,0)
859jerror_t DFDCSegment_factory::CircleFit(vector<const DFDCPseudo *>points){
860 double alpha=0.0, beta=0.0, gamma=0.0, deltax=0.0, deltay=0.0;
861 // Loop over hits to calculate alpha, beta, gamma, and delta
862 for(unsigned int i=0;i<points.size();i++){
863 const DFDCPseudo *hit = points[i];
864 double x=hit->xy.X();
865 double y=hit->xy.Y();
866 double x_sq=x*x;
867 double y_sq=y*y;
868 double x_sq_plus_y_sq=x_sq+y_sq;
869 alpha += x_sq;
870 beta += y_sq;
871 gamma += x*y;
872 deltax += 0.5*x*x_sq_plus_y_sq;
873 deltay += 0.5*y*x_sq_plus_y_sq;
874 }
875
876 // Calculate xc,yc - the center of the circle
877 double denom = alpha*beta-gamma*gamma;
878 if(fabs(denom)<1.0E-20)return UNRECOVERABLE_ERROR;
879 xc = (deltax*beta-deltay*gamma)/denom;
880 yc = (deltay*alpha-deltax*gamma)/denom;
881 rc = sqrt(xc*xc + yc*yc);
882
883 return NOERROR;
884}
885
886
887//----------------------------------------------------------------------------
888// The following routine is no longer in use:
889// Correct avalanche position along wire and incorporate drift data for
890// coordinate away from the wire using results of preliminary hit-based fit
891//
892//#define R_START 7.6
893//#define Z_TOF 617.4
894//#include "HDGEOMETRY/DLorentzMapCalibDB.h
895//#define SC_V_EFF 15.
896//#define SC_LIGHT_GUIDE 140.
897//#define SC_CENTER 38.75
898//#define TOF_BAR_LENGTH 252.0
899//#define TOF_V_EFF 15.
900//#define FDC_X_RESOLUTION 0.028
901//#define FDC_Y_RESOLUTION 0.02 //cm
902/*
903jerror_t DFDCSegment_factory::CorrectPoints(vector<DFDCPseudo*>points,
904 DMatrix XYZ){
905 // dip angle
906 double lambda=atan(tanl);
907 double alpha=M_PI/2.-lambda;
908
909 if (alpha == 0. || rc==0.) return VALUE_OUT_OF_RANGE;
910
911 // Get Bfield, needed to guess particle momentum
912 double Bx,By,Bz,B;
913 double x=XYZ(ref_plane,0);
914 double y=XYZ(ref_plane,1);
915 double z=XYZ(ref_plane,2);
916
917 bfield->GetField(x,y,z,Bx,By,Bz);
918 B=sqrt(Bx*Bx+By*By+Bz*Bz);
919
920 // Momentum and beta
921 double p=0.002998*B*rc/cos(lambda);
922 double beta=p/sqrt(p*p+0.140*0.140);
923
924 // Correct start time for propagation from (0,0)
925 double my_start_time=0.;
926 if (use_tof){
927 //my_start_time=ref_time-(Z_TOF-TARGET_Z)/sin(lambda)/beta/29.98;
928 // If we need to use the tof, the angle relative to the beam line is
929 // small enough that sin(lambda) ~ 1.
930 my_start_time=ref_time-(Z_TOF-TARGET_Z)/beta/29.98;
931 //my_start_time=0;
932 }
933 else{
934 double ratio=R_START/2./rc;
935 if (ratio<=1.)
936 my_start_time=ref_time
937 -2.*rc*asin(R_START/2./rc)*(1./cos(lambda)/beta/29.98);
938 else
939 my_start_time=ref_time
940 -rc*M_PI*(1./cos(lambda)/beta/29.98);
941
942 }
943 //my_start_time=0.;
944
945 for (unsigned int m=0;m<points.size();m++){
946 DFDCPseudo *point=points[m];
947
948 double cosangle=point->wire->udir(1);
949 double sinangle=point->wire->udir(0);
950 x=XYZ(m,0);
951 y=XYZ(m,1);
952 z=point->wire->origin.z();
953 double delta_x=0,delta_y=0;
954 // Variances based on expected resolution
955 double sigx2=FDC_X_RESOLUTION*FDC_X_RESOLUTION;
956
957 // Find difference between point on helical path and wire
958 double w=x*cosangle-y*sinangle-point->w;
959 // .. and use it to determine which sign to use for the drift time data
960 double sign=(w>0?1.:-1.);
961
962 // Correct the drift time for the flight path and convert to distance units
963 // assuming the particle is a pion
964 delta_x=sign*(point->time-fdc_track[m].s/beta/29.98-my_start_time)*55E-4;
965
966 // Variance for position along wire. Includes angle dependence from PHENIX
967 // and transverse diffusion
968 double sigy2=fdc_y_variance(alpha,delta_x);
969
970 // Next find correction to y from table of deflections
971 delta_y=lorentz_def->GetLorentzCorrection(x,y,z,alpha,delta_x);
972
973 // Fill x and y elements with corrected values
974 point->ds =-delta_y;
975 point->dw =delta_x;
976 point->x=(point->w+point->dw)*cosangle+(point->s+point->ds)*sinangle;
977 point->y=-(point->w+point->dw)*sinangle+(point->s+point->ds)*cosangle;
978 point->covxx=sigx2*cosangle*cosangle+sigy2*sinangle*sinangle;
979 point->covyy=sigx2*sinangle*sinangle+sigy2*cosangle*cosangle;
980 point->covxy=(sigy2-sigx2)*sinangle*cosangle;
981 point->status|=CORRECTED;
982 }
983 return NOERROR;
984}
985*/