Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DTrackFitterALT1.cc
Go to the documentation of this file.
1 // $Id$
2 //
3 // File: DTrackFitterALT1.cc
4 // Created: Tue Sep 2 11:18:22 EDT 2008
5 // Creator: davidl
6 //
7 //namespace{const char* GetMyID(){return "$Id$";}}
8 
9 #include <cmath>
10 using namespace std;
11 #include <math.h>
12 
13 #include <TROOT.h>
14 
15 #include <DVector3.h>
16 #include <DMatrix.h>
17 
18 #include <JANA/JEventLoop.h>
19 using namespace jana;
20 
21 #include "GlueX.h"
22 #include "DANA/DApplication.h"
23 #include "PID/DParticleID.h"
24 #include "DMagneticFieldStepper.h"
25 #include "DTrackCandidate.h"
26 #include "DTrackFitterALT1.h"
27 #include "CDC/DCDCTrackHit.h"
28 #include "FDC/DFDCPseudo.h"
29 #include "DReferenceTrajectory.h"
30 #include "DMCThrown.h"
31 #include "DMCTrackHit.h"
33 
34 extern double GetCDCCovariance(int layer1, int layer2);
35 extern double GetFDCCovariance(int layer1, int layer2);
36 extern double GetFDCCathodeCovariance(int layer1, int layer2);
37 
38 
39 // The GNU implementation of STL includes definitions of "greater" and "less"
40 // but the SunOS implementation does not. Since it is a bit of a pain to
41 // define this only for SunOS, we just define "greaterthan" and use it for
42 // all platforms/compilers. Note that this is essentially the same as the
43 // GNU definition from stl_function.h, except it does not derive from the
44 // templated "binary_function" class.
45 template<typename T>
47  public: bool operator()(const T &a, const T &b) const {return a>b;}
48 };
49 
50 
51 //------------------
52 // DTrackFitterALT1 (Constructor)
53 //------------------
55 {
56  this->loop = loop;
57 
58  // Define target center
59  target = new DCoordinateSystem();
60  target->origin.SetXYZ(0.0, 0.0, 65.0);
61  target->sdir.SetXYZ(1.0, 0.0, 0.0);
62  target->tdir.SetXYZ(0.0, 1.0, 0.0);
63  target->udir.SetXYZ(0.0, 0.0, 1.0);
64  target->L = 30.0;
65 
66  // DReferenceTrajectory objects
69 
70  DEBUG_HISTS = false;
71  DEBUG_LEVEL = 0;
72  MAX_CHISQ_DIFF = 1.0E-2;
73  MAX_FIT_ITERATIONS = 50;
74  SIGMA_CDC = 0.0150;
76  SIGMA_FDC_ANODE = 0.0200;
77  SIGMA_FDC_CATHODE = 0.0200;
78  CHISQ_GOOD_LIMIT = 2.0;
79  LEAST_SQUARES_DP = 0.0001;
80  LEAST_SQUARES_DX = 0.010;
82  LEAST_SQUARES_MAX_E2NORM = 1.0E20;
83  DEFAULT_MASS = rt->GetMass(); // Get default mass from DReferenceTrajectory class itself
84  TARGET_CONSTRAINT = false;
85  LR_FORCE_TRUTH = false;
86  USE_MULS_COVARIANCE = true;
87  USE_FDC = true;
88  USE_CDC = true;
89  USE_FDC_CATHODE = true;
90  MATERIAL_MAP_MODEL = "DGeometry";
91 
92  gPARMS->SetDefaultParameter("TRKFIT:DEBUG_HISTS", DEBUG_HISTS);
93  gPARMS->SetDefaultParameter("TRKFIT:DEBUG_LEVEL", DEBUG_LEVEL);
94  gPARMS->SetDefaultParameter("TRKFIT:MAX_CHISQ_DIFF", MAX_CHISQ_DIFF);
95  gPARMS->SetDefaultParameter("TRKFIT:MAX_FIT_ITERATIONS", MAX_FIT_ITERATIONS);
96  gPARMS->SetDefaultParameter("TRKFIT:SIGMA_CDC", SIGMA_CDC);
97  gPARMS->SetDefaultParameter("TRKFIT:CDC_USE_PARAMETERIZED_SIGMA", CDC_USE_PARAMETERIZED_SIGMA);
98  gPARMS->SetDefaultParameter("TRKFIT:SIGMA_FDC_ANODE", SIGMA_FDC_ANODE);
99  gPARMS->SetDefaultParameter("TRKFIT:SIGMA_FDC_CATHODE", SIGMA_FDC_CATHODE);
100  gPARMS->SetDefaultParameter("TRKFIT:CHISQ_GOOD_LIMIT", CHISQ_GOOD_LIMIT);
101  gPARMS->SetDefaultParameter("TRKFIT:LEAST_SQUARES_DP", LEAST_SQUARES_DP);
102  gPARMS->SetDefaultParameter("TRKFIT:LEAST_SQUARES_DX", LEAST_SQUARES_DX);
103  gPARMS->SetDefaultParameter("TRKFIT:LEAST_SQUARES_MIN_HITS", LEAST_SQUARES_MIN_HITS);
104  gPARMS->SetDefaultParameter("TRKFIT:LEAST_SQUARES_MAX_E2NORM", LEAST_SQUARES_MAX_E2NORM);
105  gPARMS->SetDefaultParameter("TRKFIT:DEFAULT_MASS", DEFAULT_MASS);
106  gPARMS->SetDefaultParameter("TRKFIT:TARGET_CONSTRAINT", TARGET_CONSTRAINT);
107  gPARMS->SetDefaultParameter("TRKFIT:LR_FORCE_TRUTH", LR_FORCE_TRUTH);
108  gPARMS->SetDefaultParameter("TRKFIT:USE_MULS_COVARIANCE", USE_MULS_COVARIANCE);
109  gPARMS->SetDefaultParameter("TRKFIT:USE_FDC", USE_FDC);
110  gPARMS->SetDefaultParameter("TRKFIT:USE_CDC", USE_CDC);
111  gPARMS->SetDefaultParameter("TRKFIT:USE_FDC_CATHODE", USE_FDC_CATHODE);
112  gPARMS->SetDefaultParameter("TRKFIT:MATERIAL_MAP_MODEL", MATERIAL_MAP_MODEL);
113 
114  // Set default mass based on configuration parameter
117 
118  // Set the geometry object pointers based on the material map
119  // specified via configuration parameter.
120  if(MATERIAL_MAP_MODEL=="DRootGeom"){
123  }else if(MATERIAL_MAP_MODEL=="DGeometry"){
124  rt->SetDGeometry(geom);
126  }else if(MATERIAL_MAP_MODEL=="NONE"){
127  rt->SetDRootGeom(NULL);
128  tmprt->SetDRootGeom(NULL);
129  rt->SetDGeometry(NULL);
130  tmprt->SetDGeometry(NULL);
131  }else{
132  _DBG_<<"ERROR: Invalid value for TRKFIT:MATERIAL_MAP_MODEL (=\""<<MATERIAL_MAP_MODEL<<"\")"<<endl;
133  exit(-1);
134  }
135 
136  cout<<__FILE__<<":"<<__LINE__<<"-------------- Least Squares TRACKING --------------"<<endl;
137 
138  DApplication* dapp = dynamic_cast<DApplication*>(loop->GetJApplication());
139  if(!dapp){
140  _DBG_<<"Cannot get DApplication from JEventLoop! (are you using a JApplication based program?)"<<endl;
141  return;
142  }
143 
144  if(DEBUG_HISTS){
145  dapp->Lock();
146 
147  // Histograms may already exist. (Another thread may have created them)
148  // Try and get pointers to the existing ones.
149  cdcdoca_vs_dist = (TH2F*)gROOT->FindObject("cdcdoca_vs_dist");
150  cdcdoca_vs_dist_vs_ring = (TH3F*)gROOT->FindObject("cdcdoca_vs_dist_vs_ring");
151  fdcdoca_vs_dist = (TH2F*)gROOT->FindObject("fdcdoca_vs_dist");
152  fdcu_vs_s = (TH2F*)gROOT->FindObject("fdcu_vs_s");
153  dist_axial = (TH1F*)gROOT->FindObject("dist_axial");
154  doca_axial = (TH1F*)gROOT->FindObject("doca_axial");
155  dist_stereo = (TH1F*)gROOT->FindObject("dist_stereo");
156  doca_stereo = (TH1F*)gROOT->FindObject("doca_stereo");
157  chisq_final_vs_initial = (TH2F*)gROOT->FindObject("chisq_final_vs_initial");
158  nhits_final_vs_initial = (TH2F*)gROOT->FindObject("nhits_final_vs_initial");
159  Npasses = (TH1F*)gROOT->FindObject("Npasses");
160  ptotal = (TH1F*)gROOT->FindObject("ptotal");
161  residuals_cdc = (TH2F*)gROOT->FindObject("residuals_cdc");
162  residuals_fdc_anode = (TH2F*)gROOT->FindObject("residuals_fdc_anode");
163  residuals_fdc_cathode = (TH2F*)gROOT->FindObject("residuals_fdc_cathode");
164  residuals_cdc_vs_s = (TH3F*)gROOT->FindObject("residuals_cdc_vs_s");
165  residuals_fdc_anode_vs_s = (TH3F*)gROOT->FindObject("residuals_fdc_anode_vs_s");
166  residuals_fdc_cathode_vs_s = (TH3F*)gROOT->FindObject("residuals_fdc_cathode_vs_s");
167  initial_chisq_vs_Npasses = (TH2F*)gROOT->FindObject("initial_chisq_vs_Npasses");
168  chisq_vs_pass = (TH2F*)gROOT->FindObject("chisq_vs_pass");
169  dchisq_vs_pass = (TH2F*)gROOT->FindObject("dchisq_vs_pass");
170  cdc_single_hit_prob = (TH1F*)gROOT->FindObject("cdc_single_hit_prob");
171  cdc_double_hit_prob = (TH1F*)gROOT->FindObject("cdc_double_hit_prob");
172  fdc_single_hit_prob = (TH1F*)gROOT->FindObject("fdc_single_hit_prob");
173  fdc_double_hit_prob = (TH1F*)gROOT->FindObject("fdc_double_hit_prob");
174  cdc_can_resi = (TH1F*)gROOT->FindObject("cdc_can_resi");
175  fdc_can_resi = (TH1F*)gROOT->FindObject("fdc_can_resi");
176  fdc_can_resi_cath = (TH1F*)gROOT->FindObject("fdc_can_resi_cath");
177  chisq_vs_p_vs_theta = (TH2F*)gROOT->FindObject("chisq_vs_p_vs_theta");
178  lambda = (TH1F*)gROOT->FindObject("lambda");
179 
180  if(!cdcdoca_vs_dist)cdcdoca_vs_dist = new TH2F("cdcdoca_vs_dist","DOCA vs. DIST",300, 0.0, 1.2, 300, 0.0, 1.2);
181  if(!cdcdoca_vs_dist_vs_ring)cdcdoca_vs_dist_vs_ring = new TH3F("cdcdoca_vs_dist_vs_ring","DOCA vs. DIST vs. ring",300, 0.0, 1.2, 300, 0.0, 1.2,23,0.5,23.5);
182  if(!fdcdoca_vs_dist)fdcdoca_vs_dist = new TH2F("fdcdoca_vs_dist","DOCA vs. DIST",500, 0.0, 2.0, 500, 0.0, 2.0);
183  if(!fdcu_vs_s)fdcu_vs_s = new TH2F("fdcu_vs_s","DOCA vs. DIST along wire",500, -60.0, 60.0, 500, -60.0, 60.0);
184  if(!dist_axial)dist_axial = new TH1F("dist_axial","Distance from drift time for axial CDC wires",300,0.0,3.0);
185  if(!doca_axial)doca_axial = new TH1F("doca_axial","DOCA of track for axial CDC wires",300,0.0,3.0);
186  if(!dist_stereo)dist_stereo = new TH1F("dist_stereo","Distance from drift time for stereo CDC wires",300,0.0,3.0);
187  if(!doca_stereo)doca_stereo = new TH1F("doca_stereo","DOCA of track for axial CDC wires",300,0.0,3.0);
188  if(!chisq_final_vs_initial)chisq_final_vs_initial = new TH2F("chisq_final_vs_initial","Final vs. initial chi-sq.",200, 0.0, 10.0,50, 0.0, 2.5);
189  if(!nhits_final_vs_initial)nhits_final_vs_initial = new TH2F("nhits_final_vs_initial","Final vs. initial nhits used in chi-sq.",30, -0.5, 29.5, 30, -0.5, 29.5);
190  if(!Npasses)Npasses = new TH1F("Npasses","Npasses", 101, -0.5, 100.5);
191  if(!ptotal)ptotal = new TH1F("ptotal","ptotal",1000, 0.1, 8.0);
192  if(!residuals_cdc)residuals_cdc = new TH2F("residuals_cdc","Residuals in CDC",1000,-2.0,2.0,24,0.5,24.5);
193  if(!residuals_fdc_anode)residuals_fdc_anode = new TH2F("residuals_fdc_anode","Residuals in FDC anodes",1000,-2.0,2.0,24,0.5,24.5);
194  if(!residuals_fdc_cathode)residuals_fdc_cathode = new TH2F("residuals_fdc_cathode","Residuals in FDC cathode",1000,-2.0,2.0,24,0.5,24.5);
195  if(!residuals_cdc_vs_s)residuals_cdc_vs_s = new TH3F("residuals_cdc_vs_s","Residuals in CDC vs. pathlength",1000,-2.0,2.0,24,0.5,24.5,100, 0.0, 800);
196  if(!residuals_fdc_anode_vs_s)residuals_fdc_anode_vs_s = new TH3F("residuals_fdc_anode_vs_s","Residuals in FDC anode vs. pathlength",1000,-2.0,2.0,24,0.5,24.5,100, 0.0, 800);
197  if(!residuals_fdc_cathode_vs_s)residuals_fdc_cathode_vs_s = new TH3F("residuals_fdc_cathode_vs_s","Residuals in FDC cathode vs. pathlength",1000,-2.0,2.0,24,0.5,24.5,100, 0.0, 800);
198  if(!initial_chisq_vs_Npasses)initial_chisq_vs_Npasses = new TH2F("initial_chisq_vs_Npasses","Initial chi-sq vs. number of iterations", 25, -0.5, 24.5, 400, 0.0, 40.0);
199  if(!chisq_vs_pass)chisq_vs_pass = new TH2F("chisq_vs_pass","Chi-sq vs. fit iteration", 25, -0.5, 24.5, 400, 0.0, 40.0);
200  if(!dchisq_vs_pass)dchisq_vs_pass = new TH2F("dchisq_vs_pass","Change in Chi-sq vs. fit iteration", 25, -0.5, 24.5, 400, 0.0, 8.0);
201  if(!cdc_single_hit_prob)cdc_single_hit_prob = new TH1F("cdc_single_hit_prob","Probability a CDC hit belongs to a track for all tracks",200,0.0,1.0);
202  if(!cdc_double_hit_prob)cdc_double_hit_prob = new TH1F("cdc_double_hit_prob","Probability a CDC hit belongs to two tracks",200,0.0,1.0);
203  if(!fdc_single_hit_prob)fdc_single_hit_prob = new TH1F("fdc_single_hit_prob","Probability a FDC hit belongs to a track for all tracks",200,0.0,1.0);
204  if(!fdc_double_hit_prob)fdc_double_hit_prob = new TH1F("fdc_double_hit_prob","Probability a FDC hit belongs to two tracks",200,0.0,1.0);
205  if(!cdc_can_resi)cdc_can_resi = new TH1F("cdc_can_resi","Residual of CDC hits with candidate tracks", 200, -1.0, 1.0);
206  if(!fdc_can_resi)fdc_can_resi = new TH1F("fdc_can_resi","Residual of FDC hits with candidate tracks", 200, -1.0, 1.0);
207  if(!fdc_can_resi_cath)fdc_can_resi_cath = new TH1F("fdc_can_resi_cath","Residual of FDC cathode hits with candidate tracks", 200, -1.0, 1.0);
208  if(!lambda)lambda = new TH1F("lambda","Scaling factor #lambda for Newton-Raphson calculated step", 2048, -2.0, 2.0);
209 
210  dapp->Unlock();
211  }
212 }
213 
214 //------------------
215 // DTrackFitterALT1 (Destructor)
216 //------------------
218 {
219  if(rt)delete rt;
220  if(tmprt)delete tmprt;
221  if(target)delete target;
222 }
223 
224 //------------------
225 // FitTrack
226 //------------------
228 {
229  /// Fit a track candidate
230 
231  // Debug message
232  if(DEBUG_LEVEL>2){
233  _DBG_<<"cdchits.size="<<cdchits.size()<<" fdchits.size="<<fdchits.size()<<endl;
234  if(fit_type==kTimeBased)_DBG_<<"============= Time-based ==============="<<endl;
235  if(fit_type==kWireBased)_DBG_<<"============= Wire-based ==============="<<endl;
236  }
237 
238  // Set mass for our DReferenceTrajectory objects
241 
242  // Do material boundary checking only for time-based tracking
243  // and only if beta*gamma is less than 1.0
244  double betagamma = input_params.momentum().Mag()/input_params.mass();
245  bool check_material_boundaries = fit_type==kTimeBased && betagamma<=1.0;
246  rt->SetCheckMaterialBoundaries(check_material_boundaries);
247  tmprt->SetCheckMaterialBoundaries(check_material_boundaries);
248 
249  // Swim reference trajectory
250  fit_status = kFitNotDone; // initialize to a safe default
252  if(mom.Mag()>12.0)mom.SetMag(8.0); // limit crazy big momenta from candidates
254 
255  if(DEBUG_LEVEL>1){
256  double chisq;
257  int Ndof;
258  ChiSq(fit_type, rt, &chisq, &Ndof);
259  _DBG_<<"starting parameters for fit: chisq="<<chisq<<" Ndof="<<Ndof<<" (chisq/Ndof="<<chisq/(double)Ndof<<") p="<<rt->swim_steps[0].mom.Mag()<<endl;
260  }
261 
262  // Iterate over fitter until it converges or we reach the
263  // maximum number of iterations
264  double last_chisq = 1.0E6;
265  int last_Ndof=1;
266  int Niterations;
267  for(Niterations=0; Niterations<MAX_FIT_ITERATIONS; Niterations++){
268 
269  hitsInfo hinfo;
270  GetHits(fit_type, rt, hinfo);
271 
272  // Optionally use the truth information from the Monte Carlo
273  // to force the correct LR choice for each hit. This is
274  // for debugging (obviously).
276 
277  switch(fit_status = LeastSquaresB(hinfo, rt)){
278  case kFitSuccess:
279  if(DEBUG_LEVEL>2)_DBG_<<"Fit succeeded ----- "<<endl;
280  break;
281  case kFitNoImprovement:
282  if(DEBUG_LEVEL>2)_DBG_<<"Unable to improve on input parameters (chisq="<<chisq<<")"<<endl;
283  break;
284  case kFitFailed:
285  if(DEBUG_LEVEL>2)_DBG_<<"Fit failed on iteration "<<Niterations<<endl;
286  if(Niterations>0){
287  if(DEBUG_LEVEL>2)_DBG_<<"Number of iterations >4. Trying to keep fit from last iteration... "<<endl;
288  chisq=last_chisq;
289  Ndof = last_Ndof;
291  break;
292  }
293  return fit_status;
294  break;
295  case kFitNotDone: // avoid compiler warnings
296  break;
297  }
298 
299  // Fill debug histos
300  if(DEBUG_HISTS){
301  chisq_vs_pass->Fill(Niterations+1, chisq/Ndof);
302  dchisq_vs_pass->Fill(Niterations+1, last_chisq/last_Ndof - chisq/Ndof);
303  }
304 
305  // If the chisq is too large, then consider it a hopeless cause
306  if(chisq/Ndof>1.0E4 || !isfinite(chisq/Ndof)){
307  if(DEBUG_LEVEL>3)_DBG_<<"Fit chisq too large on iteration "<<Niterations<<endl;
308  return fit_status=kFitFailed;
309  }
310 
311  // Check if we converged
312  if(fabs(last_chisq/last_Ndof-chisq/Ndof) < MAX_CHISQ_DIFF){
313  if(DEBUG_LEVEL>3)_DBG_<<"Fit chisq change below threshold fabs("<<last_chisq/last_Ndof<<" - "<<chisq/Ndof<<")<"<<MAX_CHISQ_DIFF<<endl;
314  break;
315  }
316  last_chisq = chisq;
317  last_Ndof = Ndof;
318  }
319 
320  if(DEBUG_LEVEL>1)_DBG_<<" Niterations="<<Niterations<<" chisq="<<chisq<<" Ndof="<<Ndof<<" (chisq/Ndof="<<chisq/(double)Ndof<<") p="<<rt->swim_steps[0].mom.Mag()<<endl;
321 
322  // At this point we must decide whether the fit succeeded or not.
323  // We'll consider the fit a success if any of the following is true:
324  //
325  // 1. We got through at least one iteration in the above loop
326  // 2. The chi-sq is less than CHISQ_GOOD_LIMIT
327  // 3. MAX_FIT_ITERATIONS is zero (for debugging)
328  bool fit_succeeded = false;
329  if(Niterations>0)fit_succeeded = true;
330  if(chisq<=CHISQ_GOOD_LIMIT)fit_succeeded = true;
331  if(MAX_FIT_ITERATIONS==0){fit_succeeded = true; fit_status=kFitSuccess;}
332  if(!fit_succeeded)return fit_status=kFitFailed;
333 
334  if(DEBUG_LEVEL>9){
335  _DBG_<<"-------- Final Chisq for track = "<<this->chisq<<" Ndof="<<this->Ndof<<endl;
336  double chisq;
337  int Ndof;
338  ChiSq(fit_type, rt, &chisq, &Ndof);
339  _DBG_<<"-------- Check chisq = "<<chisq<<" Ndof="<<Ndof<<endl;
340  }
341 
342  if(DEBUG_LEVEL>2){
343  _DBG_<<"start POCA pos: "; rt->swim_steps->origin.Print();
344  _DBG_<<"start POCA mom: "; rt->swim_steps->mom.Print();
345  ChiSq(fit_type, rt, &chisq, &Ndof);
346  _DBG_<<"start POCA chisq="<<chisq<<" Ndof="<<Ndof<<" (chisq/Ndof="<<chisq/(double)Ndof<<") p="<<rt->swim_steps[0].mom.Mag()<<endl;
347  }
348 
349  // At this point, the first point on the rt is likely not the POCA to the
350  // beamline. To find that, we swim the particle in, towards the target from
351  // the swim step closest to the first wire hit. We make sure to set the tmprt to
352  // energy *gain* for the backwards swim.
353  DVector3 vertex_pos = rt->swim_steps->origin;
354  DVector3 vertex_mom = rt->swim_steps->mom;
355  const DCoordinateSystem *first_wire = NULL;
356  if(cdchits.size()>0) first_wire=cdchits[0]->wire;
357  else if(fdchits.size()>0) first_wire=fdchits[0]->wire;
358  if(first_wire){
360  if(step){
361 #if 0
363  tmprt->Swim(step->origin, -step->mom, -rt->q, 100.0, target);
365  tmprt->GetLastDOCAPoint(vertex_pos, vertex_mom);
366  vertex_mom = -vertex_mom;
368 #endif
369  // Swim back towards target (note: we may already be past it!)
371  tmprt->Swim(rt->swim_steps->origin, -rt->swim_steps->mom, -rt->q,NULL, 100.0, target);
372 
373  // Swim swim in farward direction to target (another short swim!)
375  vertex_pos = tmprt->swim_steps[tmprt->Nswim_steps-1].origin;
376  vertex_mom = tmprt->swim_steps[tmprt->Nswim_steps-1].mom;
377  tmprt->Swim(vertex_pos, -vertex_mom, rt->q,NULL, 100.0, target);
378 
379  double locReturnValue = tmprt->DistToRT(target);
380  if((locReturnValue >= -1.0) || (locReturnValue <= 1.0)){ //else NaN
381  tmprt->GetLastDOCAPoint(vertex_pos, vertex_mom);
382 
383  // Now, swim out the rt one last time such that it starts at the POCA to
384  // the beamline. We need to do this so that we can calculate the
385  // chisq/Ndof based on the vertex parameters
386  rt->Swim(vertex_pos, vertex_mom);
387  ChiSq(fit_type, rt, &this->chisq, &this->Ndof);
388  }
389  }
390  }else{
391  _DBG_<<"NO WIRES IN CANDIDATE!! (event "<<eventnumber<<")"<<endl;
392  }
393 
394  if(DEBUG_LEVEL>2){
395  _DBG_<<"end POCA pos: "; rt->swim_steps->origin.Print();
396  _DBG_<<"end POCA mom: "; rt->swim_steps->mom.Print();
397  ChiSq(fit_type, rt, &chisq, &Ndof);
398  _DBG_<<"end POCA chisq="<<chisq<<" Ndof="<<Ndof<<" (chisq/Ndof="<<chisq/(double)Ndof<<") p="<<rt->swim_steps[0].mom.Mag()<<endl;
399  }
400 
401 
402 #if 0
403  // At this point, the first point on the rt is likely not the POCA to the
404  // beamline. To find that, we swim the particle in, towards the target from
405  // about 10 cm out along the trajectory. We make sure to set the tmprt to
406  // energy gain for the backwards swim.
408  for(int i=0; i<rt->Nswim_steps-1; i++, step++){if(step->s>10.0)break;}
410  tmprt->Swim(step->origin, -step->mom, -rt->q, 100.0, target);
412  double s;
413  tmprt->DistToRT(target, &s);
414  DVector3 vertex_mom, vertex_pos;
415  tmprt->GetLastDOCAPoint(vertex_pos, vertex_mom);
416  vertex_mom = -vertex_mom;
417 #endif
418 
419  // Copy final fit parameters into TrackFitter classes data members. Note that the chisq and Ndof
420  // members are copied in during the ChiSq() method call in LeastSquaresB().
421  fit_params.setPosition(vertex_pos);
422  fit_params.setMomentum(vertex_mom);
426 
427  // Fill debugging histos if requested
428  if(DEBUG_HISTS){
429  Npasses->Fill(Niterations);
430  initial_chisq_vs_Npasses->Fill(Niterations, chisq);
431  FillDebugHists(rt, vertex_pos, vertex_mom);
432  }
433 
434  // Debugging messages
435  if(DEBUG_LEVEL>1)_DBG_<<" -- Fit succeeded: Final params after vertex adjustment: q="<<rt->q<<" p="<<vertex_mom.Mag()<<" theta="<<vertex_mom.Theta()*57.3<<" phi="<<vertex_mom.Phi()*57.3<<" chisq="<<chisq<<" Ndof="<<Ndof<<" (chisq/Ndof="<<chisq/(double)Ndof<<")"<<endl;
436 
437  return fit_status;
438 }
439 
440 //------------------
441 // ChiSq
442 //------------------
443 double DTrackFitterALT1::ChiSq(fit_type_t fit_type, DReferenceTrajectory *rt, double *chisq_ptr, int *dof_ptr, vector<pull_t> *pulls_ptr)
444 {
445  /// Calculate the chisq for the given reference trajectory based on the hits
446  /// currently registered through the DTrackFitter base class into the cdchits
447  /// and fdchits vectors. This does not get called by the core part of the
448  /// fitter, but is used, rather, to give an "independent" value of the
449  /// chisq based only on a reference trajectory and the input hits. It is
450  /// called after the fit to calculate the final chisq.
451 
452  hitsInfo hinfo;
453  GetHits(fit_type, rt, hinfo);
454  if(LR_FORCE_TRUTH && fit_type==kTimeBased)ForceLRTruth(loop, rt, hinfo);
455 
456  vector<resiInfo> residuals;
457  GetResiInfo(rt, hinfo, residuals);
458 
459  double my_chisq = ChiSq(residuals, chisq_ptr, dof_ptr);
460  if(pulls_ptr)*pulls_ptr = pulls;
461 
462  return my_chisq;
463 }
464 
465 //------------------
466 // ChiSq
467 //------------------
468 double DTrackFitterALT1::ChiSq(vector<resiInfo> &residuals, double *chisq_ptr, int *dof_ptr)
469 {
470  // The residuals vector contains a list of only good hits, both
471  // anode and cathode, along with their measurment errors. Use these to fill
472  // the resiv and cov_meas matrices now. Fill in the cov_muls below.
473  int Nmeasurements = (int)residuals.size();
474  resiv.ResizeTo(Nmeasurements, 1);
475  cov_meas.ResizeTo(Nmeasurements, Nmeasurements);
476  cov_muls.ResizeTo(Nmeasurements, Nmeasurements);
477  pulls.clear();
478 
479  // Return "infinite" chisq if an empty residuals vector was passed.
480  if(Nmeasurements<1){
481  if(chisq_ptr)*chisq_ptr=1.0E6;
482  if(dof_ptr)*dof_ptr=1;
483  if(DEBUG_LEVEL>3)_DBG_<<"Chisq called with empty residuals vector!"<<endl;
484  return 1.0E6;
485  }
486 
487  for(unsigned int i=0; i<residuals.size(); i++){
488  resiInfo &ri = residuals[i];
489 
490  resiv[i][0] = ri.resi;
491  cov_meas[i][i] = pow(ri.err, 2.0);
492  }
493 
494  // Fill in the cov_muls matrix.
495  cov_muls.Zero();
497  // Find the first sensitive detector hit. Ignore
498  // the target point if present by checking layer!=0
499  const swim_step_t *step0 = NULL;
500  for(unsigned int i=0; i<residuals.size(); i++){
501  resiInfo &ri = residuals[i];
502  if(ri.layer<1)continue;
503  if(!ri.step)continue;
504  if( (step0==NULL) || (ri.step->s < step0->s) ){
505  step0 = ri.step;
506  }
507  }
508 
509  if(step0){
510  // Loop over all residuals
511  for(unsigned int i=0; i<residuals.size(); i++){
512  const swim_step_t *stepA = residuals[i].step;
513  if(!stepA)continue;
514  // resiInfo &riA = residuals[i]; // see 2010/07/12 note below
515 
516  // Loop over all residuals
517  for(unsigned int j=i; j<residuals.size(); j++){
518  const swim_step_t *stepB = residuals[j].step;
519  if(!stepB)continue;
520  // resiInfo &riB = residuals[j]; // see 2010/07/12 note below
521 
522  // Correlations are very hard to get correct given the left-right
523  // ambiguity which determines the sign of the correlation.
524  // Because of this, only include the diagonal elements of the
525  // covariance matrix. Attempts were made to do otherwise, but they
526  // failed. The code is left here in case we need to try it again
527  // at a later time.
528  if(i!=j)continue;
529 
530  // Correlations between A and B are due only to material between
531  // the first detector and the most upstream of A or B.
532  double sA = stepA->s;
533  double sB = stepB->s;
534  const swim_step_t *step_end = sA<sB ? stepA:stepB;
535 
536  if(step0->s>step_end->s)continue; // Bullet proof
537 
538  // Need a comment here to explain this ...
539  double itheta02 = step_end->itheta02 - step0->itheta02;
540  double itheta02s = step_end->itheta02s - step0->itheta02s;
541  double itheta02s2 = step_end->itheta02s2 - step0->itheta02s2;
542  double sigmaAB = sA*sB*itheta02 - (sA+sB)*itheta02s + itheta02s2;
543 
544  // sigmaAB represents the magnitude of the covariance, but not the
545  // sign.
546  //
547  // For wires generally in the same direction, the sign
548  // should be positive if they are on the same side of the wire
549  // but negative if they are on opposite sides.
550  //
551  // For wires that are orhogonal (like a CDC is to an FDC wire), the
552  // the procedure is not so clear.
553 
554  // Note: 2010/07/12 DL
555  // The following code is unneeded since we are not implementing off
556  // diagonal elements of the covariance matrix. It was noted by Simon,
557  // however, that the value of "sign" was sometimes being calculated
558  // as negative, even for on diagonal elements leading to overall
559  // worse resolutions. Upon re-reading the comment below, I'm so sure
560  // I believe the method to be correct anyway. Hence, I'm commenting
561  // it and the corresponding code out, but leaving it here in case this
562  // issue gets revisited in the future.
563  //
564  // // Find LR of this hit.
565  // // Vector pointing from origin of wire to step position crossed into
566  // // wire direction gives a vector that will either be pointing
567  // // generally in the direction of the momentum or opposite to it.
568  // // Take dot product of above described vectors for each hit
569  // // use it to determine L or R.
570  // DVector3 crossA = (stepA->origin - riA.hit->wire->origin).Cross(riA.hit->wire->udir);
571  // DVector3 crossB = (stepB->origin - riB.hit->wire->origin).Cross(riB.hit->wire->udir);
572  // double sides_angle = crossA.Angle(crossB)*57.3;
573  // double sign = fabs(sides_angle) < 90.0 ? +1.0:-1.0;
574  double sign = +1.0;
575 
576  cov_muls[i][j] = cov_muls[j][i] = sign*sigmaAB;
577  }
578  }
579  }
580  }
581 
582  // Multiply resiv with inverse of total error matrix to get chisq = r^T (cov_meas+cov_muls)^-1 r)
583  DMatrix resiv_t(DMatrix::kTransposed, resiv);
584  DMatrix W(DMatrix::kInverted, cov_meas+cov_muls);
585  DMatrix chisqM(resiv_t*W*resiv);
586  double chisq = chisqM[0][0];
587  int Ndof = (int)residuals.size() - 5; // assume 5 fit parameters
588  weights.ResizeTo(W);
589  weights = W;
590 
591  // Copy pulls into pulls vector
592  for(unsigned int i=0; i<residuals.size(); i++){
593  double err = sqrt(cov_meas[i][i]+cov_muls[i][i]);
594  pulls.push_back(pull_t(resiv[i][0], err, residuals[i].step->s));
595  }
596 
597  if(DEBUG_LEVEL>100 || (DEBUG_LEVEL>10 && !isfinite(chisq)))PrintChisqElements(resiv, cov_meas, cov_muls, weights);
598 
599  // If the caller supplied pointers to chisq and dof variables, copy the values into them
600  if(chisq_ptr)*chisq_ptr = chisq;
601  if(dof_ptr)*dof_ptr = Ndof; // assume 5 fit parameters
602 
603  // If it turns out the dof is zero, return 1.0E6. Otherwise, return
604  // the chisq/dof
605  return Ndof<2 ? 1.0E6:chisq/(double)Ndof;
606 }
607 
608 //------------------
609 // GetHits
610 //------------------
612 {
613 
614  // -- Target --
615  if(TARGET_CONSTRAINT){
616  hitInfo hi;
617  hi.wire = target;
618  hi.dist = 0.0;
619  hi.err = 0.1; // 1mm beam width
620  hi.u_dist = 0.0;
621  hi.u_err = 0.0;
622  hi.good = hi.good_u = false;
623  hinfo.push_back(hi);
624  }
625 
626  // --- CDC ---
627  if(USE_CDC){
628  for(unsigned int i=0; i<cdchits.size(); i++){
629  const DCDCTrackHit *hit = cdchits[i];
630  const DCoordinateSystem *wire = hit->wire;
631  hitInfo hi;
632 
633  hi.wire = wire;
634  hi.u_dist = 0.0;
635  hi.u_err = 0.0;
636  hi.good = hi.good_u = false;
637 
638  // Fill in shifts and errs vectors based on whether we're doing
639  // hit-based or time-based tracking
640  if(fit_type==kWireBased){
641  // If we're doing hit-based tracking then only the wire positions
642  // are used and the drift time info is ignored.
643  // NOTE: The track quality itself goes into the residual resoultion
644  // and so we use something larger than the variance over an evenly
645  // illuminated cell size (commented out). The value of 0.31 is
646  // empirical from forward (2-40 degree) pi+ tracks when MULS was
647  // off. This will likely need to be higher when MULS is on...
648  hi.dist = 0.0;
649  hi.err = 0.45; // empirical. (see note above)
650  //hi.err = 0.8/sqrt(12.0); // variance for evenly illuminated straw
651  }else{
652  // Find the DOCA point for the RT and use the momentum direction
653  // there and the wire direction to determine the "shift".
654  // Note that whether the shift is to the left or to the right
655  // is not decided here. That ambiguity is left to be resolved later
656  // by applying a minus sign (or not) to the shift.
657  DVector3 pos_doca, mom_doca;
658  double s;
659  rt->DistToRT(wire, &s);
660  rt->GetLastDOCAPoint(pos_doca, mom_doca);
661 
662  // The magnitude of the shift is based on the drift time. The
663  // value of the dist member of the DCDCTrackHit object does not
664  // subtract out the TOF. This can add 50-100 microns to the
665  // resolution in the CDC. Here, we actually can calculate the TOF
666  // (for a given mass hypothesis).
667  double mass = rt->GetMass();
668  double beta = 1.0/sqrt(1.0 + pow(mass/mom_doca.Mag(), 2.0))*2.998E10;
669  double tof = s/beta/1.0E-9; // in ns
670  hi.dist = hit->dist*((hit->tdrift-tof)/hit->tdrift);
671  hi.err = SIGMA_CDC;
672 
673  // Default is to use parameterized sigma, by allow user to specify
674  // using constant sigma.
676  // The following is from a fit to Yves' numbers circa Aug 2009. The values fit were
677  // resolution (microns) vs. drift distance (mm).
678  // par[8] = {699.875, -559.056, 149.391, 25.6929, -22.0238, 4.75091, -0.452373, 0.0163858};
679  double x = hi.dist;
680  if(x<0.0)x=0.0; // this can be negative due to tof subtraction above.
681  //double sigma_d = (699.875) + x*((-559.056) + x*((149.391) + x*((25.6929) + x*((-22.0238) + x*((4.75091) + x*((-0.452373) + x*((0.0163858))))))));
682  double sigma_d = 108.55 + 7.62391*x + 556.176*exp(-(1.12566)*pow(x,1.29645));
683  hi.err = sigma_d/10000.0;
684  }
685  }
686  hinfo.push_back(hi);
687  }
688  } // USE_CDC
689 
690  // --- FDC ---
691  if(USE_FDC){
692  for(unsigned int i=0; i<fdchits.size(); i++){
693  const DFDCPseudo *hit = fdchits[i];
694  const DCoordinateSystem *wire = hit->wire;
695  hitInfo hi;
696 
697  hi.wire = wire;
698  hi.good = hi.good_u = false;
699 
700  // Fill in shifts and errs vectors based on whether we're doing
701  // hit-based or time-based tracking
702  if(fit_type==kWireBased){
703  // If we're doing hit-based tracking then only the wire positions
704  // are used and the drift time info is ignored.
705  // NOTE: The track quality itself goes into the residual resoultion
706  // and so we use something larger than the variance over an evenly
707  // illuminated cell size (commented out). The value of 0.30 is
708  // empirical from forward (2-40 degree) pi+ tracks when MULS was
709  hi.dist = 0.0;
710  hi.err = 0.30; // emprical. (see note above)
711  //hi.err = 0.5/sqrt(12.0); // variance for evenly illuminated cell - anode
712  hi.u_dist = 0.0;
713  hi.u_err = 0.0; // variance for evenly illuminated cell - cathode
714  }else{
715  // Find the DOCA point for the RT and use the momentum direction
716  // there and the wire direction to determine the "shift".
717  // Note that whether the shift is to the left or to the right
718  // is not decided here. That ambiguity is left to be resolved later
719  // by applying a minus sign (or not) to the shift.
720  DVector3 pos_doca, mom_doca;
721  double s;
722  rt->DistToRT(wire, &s);
723  rt->GetLastDOCAPoint(pos_doca, mom_doca);
724 
725  // The magnitude of the shift is based on the drift time. The
726  // value of the dist member of the DCDCTrackHit object does not
727  // subtract out the TOF. This can add 50-100 microns to the
728  // resolution in the CDC. Here, we actually can calculate the TOF
729  // (for a given mass hypothesis).
730  double mass = rt->GetMass();
731  double beta = 1.0/sqrt(1.0 + pow(mass/mom_doca.Mag(), 2.0))*2.998E10;
732  double tof = s/beta/1.0E-9; // in ns
733  hi.dist = 55E-4*(hit->time-tof);
734  hi.err = SIGMA_FDC_ANODE;
735  /*
736  if(USE_FDC_CATHODE){
737  // Find whether the track is on the "left" or "right" of the wire
738  DVector3 shift = wire->udir.Cross(mom_doca);
739  if(shift.Mag()!=0.0)shift.SetMag(1.0);
740  double u = rt->GetLastDistAlongWire();
741  DVector3 pos_wire = wire->origin + u*wire->udir;
742  double LRsign = shift.Dot(pos_doca-pos_wire)<0.0 ? +1.0:-1.0;
743 
744  // Lorentz corrected poisition along the wire is contained in x,y
745  // values, BUT, it is based on a left-right decision of the track
746  // segment. This may or may not be the same as the global track.
747  // As such, we have to determine the correction for our track.
748  //DVector3 wpos(hit->x, hit->y, wire->origin.Z());
749  //DVector3 wdiff = wpos - wire->origin;
750  //double u_corr = wire->udir.Dot(wdiff);
751  double alpha = mom_doca.Angle(DVector3(0,0,1));
752  hi.u_lorentz = LRsign*lorentz_def->GetLorentzCorrection(pos_doca.X(), pos_doca.Y(), pos_doca.Z(), alpha, hi.dist);
753  hi.u_dist = hit->s;
754  hi.u_err = SIGMA_FDC_CATHODE;
755  }else{
756  // User specified not to use FDC cathode information in the fit.
757  */
758  hi.u_dist = 0.0;
759  hi.u_err = 0.0; // setting u_err to zero means it's excluded from chi-sq
760  // }
761  }
762  hinfo.push_back(hi);
763  }
764  } // USE_FDC
765 }
766 
767 
768 //------------------
769 // GetResiInfo
770 //------------------
771 vector<bool> DTrackFitterALT1::GetResiInfo(DMatrix &state, const swim_step_t *start_step, DReferenceTrajectory *rt, hitsInfo &hinfo, vector<resiInfo> &residuals)
772 {
773  /// Calculate the chi-squared for a track specified by state relative to the
774  /// given reference trajectory. This is just a wrapper for
775  /// ChiSq(DReferenceTrajectory *rt, vector<const DCoordinateSystem*> &wires, vector<DVector3> &shifts, vector<double> &errs, vector<double> &chisqv)
776  /// that accepts the state vector and re-swims the trajectory.
777 
778  // In case we need to return early
779  int Nhits=0;
780  for(unsigned int i=0; i<hinfo.size(); i++){Nhits++; if(hinfo[i].u_err!=0.0)Nhits++;}
781  vector<bool> good_none(Nhits, false);
782 
783  // "v" direction is perpendicular to both the rt direction and the
784  // x-direction. See LeastSquares() for more.
785  DVector3 vdir = start_step->sdir.Cross(start_step->mom);
786  if(vdir.Mag()!=0.0)vdir.SetMag(1.0);
787 
788  DVector3 pos = start_step->origin
789  + state[state_x ][0]*start_step->sdir
790  + state[state_v ][0]*vdir;
791  DVector3 mom = state[state_px][0]*start_step->sdir
792  + state[state_py][0]*start_step->tdir
793  + state[state_pz][0]*start_step->udir;
794 
795  if(!rt){
796  _DBG_<<"NULL pointer passed for DReferenceTrajectory object!"<<endl;
797  return good_none;
798  }
799 
800  if(pos.Mag()>200.0 || fabs(state[state_x ][0])>100.0 || fabs(state[state_v ][0])>100.0){
801  if(DEBUG_LEVEL>3)_DBG_<<"state values out of range"<<endl;
802  if(DEBUG_LEVEL>6){
803  pos.Print();
804  mom.Print();
805  _DBG_<<"state[state_x ][0]="<<state[state_x ][0]<<" state[state_v ][0]="<<state[state_x ][0]<<endl;
806  }
807  return good_none;
808  }
809 
810  // Swim the trajectory with the specified state
811  rt->Swim(pos,mom);
812 
813  // Sometimes, a bad state vector is passed that leads to referance trajectory with no steps.
814  if(rt->Nswim_steps<1){
815  residuals.clear();
816  return good_none;
817  }
818 
819  return GetResiInfo(rt, hinfo, residuals);
820 }
821 
822 //------------------
823 // GetResiInfo
824 //------------------
825 vector<bool> DTrackFitterALT1::GetResiInfo(DReferenceTrajectory *rt, hitsInfo &hinfo, vector<resiInfo> &residuals)
826 {
827  // Make a serialized list of "good" hits as we sparsely fill the residuals
828  // container with only the good ones.
829  vector<bool> good;
830 
831  // Loop over wires hit. Make lists of finite residuals with layer numbers
832  // from which to build the actual matrices used to calculate chisq below.
833  residuals.clear();
834  for(unsigned int i=0; i<hinfo.size(); i++){
835  hitInfo &hi = hinfo[i];
836  hi.good = hi.good_u = false;
837 
838  const DCoordinateSystem *wire = hi.wire;
839 
840  // Figure out whether this is a CDC or FDC wire. Note that
841  // it could be neither if the target constraint is used.
842  const DFDCWire *fdcwire = dynamic_cast<const DFDCWire*>(wire);
843  const DCDCWire *cdcwire = dynamic_cast<const DCDCWire*>(wire);
844 
845  // Get distance of the wire from the reference trajectory and the
846  // distance s along the track to the point of closest approach.
847  double s;
848  double d = rt->DistToRT(wire, &s);
849 
850  // Residual. If we're on the correct side of the wire, then this is
851  // dist-doca. If we're on the incorrect side of the wire, then this
852  // is -dist-doca. Prior to calling us, the value of hi.dist will have
853  // a sign that has already been assigned to indicate the side of the wire
854  // the track is believed to be on.
855  double resi = hi.dist - d;
856  if(isfinite(resi)){
857  resiInfo ri;
858  ri.hit = &hi;
859  ri.layer = cdcwire ? cdcwire->ring:(fdcwire ? fdcwire->layer:0);
861  ri.resi = resi;
862  ri.err = hi.err;
863  ri.step = rt->GetLastSwimStep();
864  hi.good = true;
865  residuals.push_back(ri);
866  good.push_back(true);
867  }else{
868  good.push_back(false);
869  }
870 
871  // Also add residual along the wire. If the value of u_err is zero
872  // that indicates no measurement was made along the wire for this hit.
873  if(hi.u_err!=0.0){
874  // The sign of hi.dist indicates whether we want to treat this hit as
875  // being on the same side of the wire as the track(+) or the opposite
876  // side (-). In the latter case, we need to apply the Lorentz correction
877  // to the position along the wire in the opposite direction than we
878  // would otherwise. Set the sign of the Lorentz deflection based on the
879  // sign of hi.dist.
880  double LRsign = hi.dist<0.0 ? -1.0:1.0;
881 
882  double u = rt->GetLastDistAlongWire();
883  double u_corrected = hi.u_dist + LRsign*hi.u_lorentz;
884  double resic = u - u_corrected;
885  if(isfinite(resic)){
886  resiInfo ri;
887  ri.hit = &hi;
888  ri.layer = fdcwire ? fdcwire->layer:0;
890  ri.resi = resic;
891  ri.err = hi.u_err;
892  ri.step = rt->GetLastSwimStep();
893  hi.good_u = true;
894  residuals.push_back(ri);
895  good.push_back(true);
896  }else{
897  good.push_back(false);
898  }
899  }
900  }
901 
902  return good;
903 }
904 
905 //------------------
906 // LeastSquaresB
907 //------------------
909 {
910  /// Fit the track with starting parameters given in the first step
911  /// of the reference trajectory rt. On return, the reference
912  /// trajectory rt will represent the final fit parameters and
913  /// chisq, Ndof, resiv, cov_meas, cov_muls, and cov_parm will be
914  /// filled based on the fit results.
915  ///
916  /// This determines the best fit of the track using the least squares method
917  /// described by R. Mankel Rep. Prog. Phys. 67 (2004) 553-622 pg 565.
918  /// Since it uses a linear approximation for the chisq dependance on
919  /// the fit parameters, several calls may be required for convergence.
920 
921  // Initialize the chisq and Ndof data members in case we need to bail early
922  this->chisq = 1.0E6;
923  this->Ndof = 0;
924 
925  // Make sure RT is not empty
926  if(rt->Nswim_steps<1)return kFitFailed;
927 
928  // For fitting, we want to define a coordinate system very similar to the
929  // Reference Trajectory coordinate system. The difference is that we want
930  // the position to be defined in a plane perpendicular to the momentum.
931  // The RT x-direction is in this plane, but the momentum itself lies
932  // somewhere in the Y/Z plane so that neither Y nor Z makes a good choice
933  // for the second postion dimension. We will call the second coordinate in
934  // the perpendicular plane "v" which is the coordinate along the axis that
935  // is perpendicular to both the x-direction and the momentum direction.
936  swim_step_t &start_step = rt->swim_steps[0];
937  DVector3 pos = start_step.origin;
938  DVector3 mom = start_step.mom;
939 
940  // Get the chi-squared vector for the initial reference trajectory
941  double initial_chisq;
942  int initial_Ndof;
943  vector<resiInfo> tmpresiduals;
944  vector<bool> good_initial = GetResiInfo(rt, hinfo, tmpresiduals);
945  double initial_chisq_per_dof = ChiSq(tmpresiduals, &initial_chisq, &initial_Ndof);
946  DMatrix resiv_initial(resiv);
947  DMatrix cov_meas_initial(cov_meas);
948  DMatrix cov_muls_initial(cov_muls);
949  DMatrix weights_initial(weights);
950 
951  // Check that the initial chisq is reasonable before continuing
952  if(initial_Ndof<1){
953  if(DEBUG_LEVEL>0)_DBG_<<"Initial Ndof<1. Aborting fit."<<endl;
954  return kFitFailed;
955  }
956 
957  // Because we have a complicated non-linear system, we take the derivatives
958  // numerically.
959  //
960  // Note that in the calculations of the deltas below,
961  // the change in state should be set first and the value
962  // of deltas[...] calculated from that. See Numerical
963  // Recipes in C 2nd ed. section 5.7 ppg. 186-189.
964  const int Nparameters = 5;
965  double deltas[Nparameters];
966  DMatrix state(5,1);
967  switch(Nparameters){
968  case 5: state[state_v ][0] = 0.0;
969  case 4: state[state_x ][0] = 0.0;
970  case 3: state[state_pz ][0] = mom.Dot(start_step.udir);
971  case 2: state[state_py ][0] = mom.Dot(start_step.tdir);
972  case 1: state[state_px ][0] = mom.Dot(start_step.sdir);
973  }
974 
975  // For the swimming below, we use a second reference trajectory so as
976  // to preserve the original. Set the charge here. The rest of the
977  // parameters (starting position and momentum) will be set using
978  // values from the state vector.
979  tmprt->q = rt->q;
980 
981  // dpx : tweak by 0.0001
982  DMatrix state_dpx = state;
983  state_dpx[state_px][0] += LEAST_SQUARES_DP;
984  deltas[state_px] = state_dpx[state_px][0] - state[state_px][0];
985  vector<bool> good_px = GetResiInfo(state_dpx, &start_step, tmprt, hinfo, tmpresiduals);
986  double chisq_dpx = ChiSq(tmpresiduals);
987  DMatrix resiv_dpx_hi(resiv);
988  DMatrix &resiv_dpx_lo = resiv_initial;
989 
990  // dpy : tweak by 0.0001
991  DMatrix state_dpy = state;
992  state_dpy[state_py][0] += LEAST_SQUARES_DP;
993  deltas[state_py] = state_dpy[state_py][0] - state[state_py][0];
994  vector<bool> good_py = GetResiInfo(state_dpy, &start_step, tmprt, hinfo, tmpresiduals);
995  double chisq_dpy = ChiSq(tmpresiduals);
996  DMatrix resiv_dpy_hi(resiv);
997  DMatrix &resiv_dpy_lo = resiv_initial;
998 
999  // dpz : tweak by 0.0001
1000  DMatrix state_dpz = state;
1001  state_dpz[state_pz][0] += LEAST_SQUARES_DP;
1002  deltas[state_pz] = state_dpz[state_pz][0] - state[state_pz][0];
1003  vector<bool> good_pz = GetResiInfo(state_dpz, &start_step, tmprt, hinfo, tmpresiduals);
1004  double chisq_dpz = ChiSq(tmpresiduals);
1005  DMatrix resiv_dpz_hi(resiv);
1006  DMatrix &resiv_dpz_lo = resiv_initial;
1007 
1008  // dv : tweak by 0.01
1009  DMatrix state_dv = state;
1010  state_dv[state_v][0] += LEAST_SQUARES_DX;
1011  deltas[state_v] = state_dv[state_v][0] - state[state_v][0];
1012  vector<bool> good_v = GetResiInfo(state_dv, &start_step, tmprt, hinfo, tmpresiduals);
1013  double chisq_dv = ChiSq(tmpresiduals);
1014  DMatrix resiv_dv_hi(resiv);
1015  DMatrix &resiv_dv_lo = resiv_initial;
1016 
1017  // dx : tweak by 0.01
1018  DMatrix state_dx = state;
1019  state_dx[state_x][0] += LEAST_SQUARES_DX;
1020  deltas[state_x] = state_dx[state_x][0] - state[state_x][0];
1021  vector<bool> good_x = GetResiInfo(state_dx, &start_step, tmprt, hinfo, tmpresiduals);
1022  double chisq_dx = ChiSq(tmpresiduals);
1023  DMatrix resiv_dx_hi(resiv);
1024  DMatrix &resiv_dx_lo = resiv_initial;
1025 
1026  // Verify all of the "good" vectors are of the same length
1027  unsigned int size_good = good_initial.size();
1028  if( (good_px.size() != size_good)
1029  || (good_py.size() != size_good)
1030  || (good_pz.size() != size_good)
1031  || (good_v.size() != size_good)
1032  || (good_x.size() != size_good)){
1033  _DBG_<<"Size of \"good\" vectors don't match! size_good="<<size_good<<endl;
1034  _DBG_<<"good_px.size()="<<good_px.size()<<endl;
1035  _DBG_<<"good_py.size()="<<good_py.size()<<endl;
1036  _DBG_<<"good_pz.size()="<<good_pz.size()<<endl;
1037  _DBG_<<" good_v.size()="<<good_v.size()<<endl;
1038  _DBG_<<" good_x.size()="<<good_x.size()<<endl;
1039  return kFitFailed;
1040  }
1041 
1042  // We need to get a list of hits that are good for all of the tweaked
1043  // tracks as well as the initial track.
1044  unsigned int Ngood = 0;
1045  vector<bool> good_all;
1046  for(unsigned int i=0; i<size_good; i++){
1047  bool isgood = true;
1048  isgood &= good_initial[i];
1049  isgood &= good_px[i];
1050  isgood &= good_py[i];
1051  isgood &= good_pz[i];
1052  isgood &= good_v[i];
1053  isgood &= good_x[i];
1054  good_all.push_back(isgood);
1055  if(isgood)Ngood++;
1056  }
1057 
1058  // Make sure there is a minimum number of hits before attempting a fit
1059  if(Ngood<LEAST_SQUARES_MIN_HITS){
1060  if(DEBUG_LEVEL>0)_DBG_<<"Not enough good hits to do fit. Aborting..."<<endl;
1061  return kFitFailed;
1062  }
1063 
1064  // Use the good_all map to filter out hits for each residual vector
1065  // for which somebody else did not have a good hit.
1066  FilterGood(resiv_initial, good_initial, good_all);
1067  FilterGood(resiv_dpx_hi , good_px, good_all);
1068  FilterGood(resiv_dpy_hi , good_py, good_all);
1069  FilterGood(resiv_dpz_hi , good_pz, good_all);
1070  FilterGood(resiv_dv_hi , good_v , good_all);
1071  FilterGood(resiv_dx_hi , good_x , good_all);
1072  FilterGood(weights_initial , good_x , good_all);
1073 
1074  // Here, we check that the the residual vectors are of the same
1075  // dimension for all tweaked tracks and the initial track so that we
1076  // can proceed with building the fit matrices below.
1077  int Nhits = resiv_initial.GetNrows();
1078  if( (resiv_dpx_hi.GetNrows() != Nhits)
1079  || (resiv_dpy_hi.GetNrows() != Nhits)
1080  || (resiv_dpz_hi.GetNrows() != Nhits)
1081  || (resiv_dx_hi.GetNrows() != Nhits)
1082  || (resiv_dv_hi.GetNrows() != Nhits)){
1083  _DBG_<<"Size of residual vectors don't match! Nhits="<<Nhits<<endl;
1084  _DBG_<<"resiv_dpx_hi.GetNrows()="<<resiv_dpx_hi.GetNrows()<<endl;
1085  _DBG_<<"resiv_dpy_hi.GetNrows()="<<resiv_dpy_hi.GetNrows()<<endl;
1086  _DBG_<<"resiv_dpz_hi.GetNrows()="<<resiv_dpz_hi.GetNrows()<<endl;
1087  _DBG_<<" resiv_dx_hi.GetNrows()="<<resiv_dx_hi.GetNrows()<<endl;
1088  _DBG_<<" resiv_dv_hi.GetNrows()="<<resiv_dv_hi.GetNrows()<<endl;
1089  return kFitFailed;
1090  }
1091 
1092  // Print some debug messages
1093  if(DEBUG_LEVEL>4){
1094  _DBG_<<"initial_chisq_per_dof="<<initial_chisq_per_dof<<endl;
1095  _DBG_<<"chisq_dpx="<<chisq_dpx<<endl;
1096  _DBG_<<"chisq_dpy="<<chisq_dpy<<endl;
1097  _DBG_<<"chisq_dpz="<<chisq_dpz<<endl;
1098  _DBG_<<"chisq_dv="<<chisq_dv<<endl;
1099  _DBG_<<"chisq_dx="<<chisq_dx<<endl;
1100  if(DEBUG_LEVEL>10){
1101  _DBG_<<"hit\tinitial\tpx \tpy \tpz \tx \tv"<<endl;
1102  for(int j=0; j<resiv_initial.GetNrows(); j++){
1103  cout<<j<<"\t";
1104  cout<<resiv_initial[j][0]/sqrt(cov_meas[j][j])<<"\t";
1105  cout<<resiv_dpx_hi[j][0]/sqrt(cov_meas[j][j])<<"\t";
1106  cout<<resiv_dpy_hi[j][0]/sqrt(cov_meas[j][j])<<"\t";
1107  cout<<resiv_dpz_hi[j][0]/sqrt(cov_meas[j][j])<<"\t";
1108  cout<<resiv_dv_hi[j][0]/sqrt(cov_meas[j][j])<<"\t";
1109  cout<<resiv_dx_hi[j][0]/sqrt(cov_meas[j][j])<<endl;
1110  }
1111  }
1112  }
1113 
1114  // Build "F" matrix of derivatives
1115  DMatrix F(Nhits,Nparameters);
1116  for(int i=0; i<Nhits; i++){
1117  switch(Nparameters){
1118  // Note: This is a funny way to use a switch!
1119  case 5: F[i][state_v ] = (resiv_dv_hi[i][0]-resiv_dv_lo[i][0])/deltas[state_v];
1120  case 4: F[i][state_x ] = (resiv_dx_hi[i][0]-resiv_dx_lo[i][0])/deltas[state_x];
1121  case 3: F[i][state_pz] = (resiv_dpz_hi[i][0]-resiv_dpz_lo[i][0])/deltas[state_pz];
1122  case 2: F[i][state_py] = (resiv_dpy_hi[i][0]-resiv_dpy_lo[i][0])/deltas[state_py];
1123  case 1: F[i][state_px] = (resiv_dpx_hi[i][0]-resiv_dpx_lo[i][0])/deltas[state_px];
1124  }
1125  }
1126 
1127  // Sometimes, "F" has lots of values like 1.44E+09 indicating a problem (I think comming
1128  // from some nan values floating around.) Anyway, in these cases, the E2Norm value is
1129  // quite large (>1E+18) which we can use to punt now. In reality, we do this to avoid
1130  // ROOT error messages about a matrix being singular when Ft*Vinv*F is inverted below.
1131  if(F.E2Norm()>1.0E18){
1132  if(DEBUG_LEVEL>1){
1133  _DBG_<<" -- F matrix E2Norm out of range(E2Norm="<<F.E2Norm()<<" max="<<1.0E18<<")"<<endl;
1134  }
1135  return kFitFailed;
1136  }
1137 
1138  // Transpose of "F" matrix
1139  DMatrix Ft(DMatrix::kTransposed, F);
1140 
1141  // Calculate the "B" matrix using the weights from the initial chisq
1142  DMatrix &Vinv = weights_initial; // Stick with Mankel naming convention
1143  DMatrix B(DMatrix::kInverted, Ft*Vinv*F);
1144 
1145  // If the inversion failed altogether then the invalid flag
1146  // will be set on the matrix. In these cases, we're dead.
1147  if(!B.IsValid()){
1148  if(DEBUG_LEVEL>1)_DBG_<<" -- B matrix invalid"<<endl;
1149  return kFitFailed;
1150  }
1151 
1152  // The "B" matrix happens to be the covariance matrix of the
1153  // state parameters. A problem sometimes occurs where one or
1154  // more elements of B are very large. This tends to happen
1155  // when a column of F is essentially all zeros making the
1156  // matrix un-invertable. What we should really do in these
1157  // cases is check beforehand and drop the bad column(s)
1158  // before trying to invert. That will add complication that
1159  // I don't want to introduce quite yet. What we do now
1160  // is check for it and punt rather than return a nonsensical
1161  // value.
1162  if(B.E2Norm() > LEAST_SQUARES_MAX_E2NORM){
1163  if(DEBUG_LEVEL>1){
1164  _DBG_<<" -- B matrix E2Norm out of range(E2Norm="<<B.E2Norm()<<" max="<<LEAST_SQUARES_MAX_E2NORM<<")"<<endl;
1165  cout<<"--- B ---"<<endl;
1166  B.Print();
1167  }
1168  return kFitFailed;
1169  }
1170 
1171  // Copy the B matrix into cov_parm to later copy into DTrack
1172  cov_parm.ResizeTo(B);
1173  cov_parm = B;
1174 
1175  // Calculate step direction and magnitude
1176  DMatrix delta_state = B*Ft*Vinv*resiv_initial;
1177 
1178  // The following is based on Numerical Recipes in C 2nd Ed.
1179  // ppg. 384-385.
1180  //
1181  // We now have the "direction" by which to step in the-d
1182  // parameter space as well as an amplitude by which to
1183  // step in "delta_state". A potential problem is that
1184  // we can over-step such that we end up at a worse
1185  // chi-squared value. To address this, we try taking
1186  // the full step, but if we end up at a worse chi-sq
1187  // then we backtrack and take a smaller step until
1188  // we see the chi-sq improve.
1189  double min_chisq_per_dof = initial_chisq_per_dof;
1190  double min_lambda = 0.0;
1191  double lambda = -1.0;
1192  int Ntrys = 0;
1193  int max_trys = 6;
1194  DMatrix new_state(5,1);
1195  for(; Ntrys<max_trys; Ntrys++){
1196 
1197  // Scale the delta by lambda to take a partial step (except the 1st iteration where lambda is 1)
1198  for(int i=0; i<Nparameters; i++)new_state[i][0] = state[i][0] + delta_state[i][0]*lambda;
1199 
1200  GetResiInfo(new_state, &start_step, tmprt, hinfo, tmpresiduals);
1201  double chisq_per_dof = ChiSq(tmpresiduals);
1202 
1203  if(chisq_per_dof<min_chisq_per_dof){
1204  min_chisq_per_dof = chisq_per_dof;
1205  min_lambda = lambda;
1206  }
1207 
1208  // If we're at a lower chi-sq then we're done
1209  if(DEBUG_LEVEL>4)_DBG_<<" -- initial_chisq_per_dof="<<initial_chisq_per_dof<<" new chisq_per_dof="<<chisq_per_dof<<" nhits="<<resiv.GetNrows()<<" p="<<tmprt->swim_steps[0].mom.Mag()<<" lambda="<<lambda<<endl;
1210  if(chisq_per_dof-initial_chisq_per_dof < 0.1 && chisq_per_dof<2.0)break;
1211 
1212  if(chisq_per_dof<initial_chisq_per_dof)break;
1213 
1214  // Chi-sq was increased, try a smaller step on the next iteration
1215  lambda/=2.0;
1216  }
1217 
1218  // If we failed to find a better Chi-Sq above, maybe we were looking
1219  // in the wrong direction(??) Try looking in the opposite direction.
1220  //if(Ntrys>=max_trys && (min_chisq_per_dof>=initial_chisq_per_dof || min_chisq_per_dof>1.0)){
1221  if(Ntrys>=max_trys){
1222  lambda = 1.0/4.0;
1223  for(int j=0; j<3; j++, Ntrys++){
1224 
1225  // Scale the delta by lambda to take a partial step (except the 1st iteration where lambda is 1)
1226  for(int i=0; i<Nparameters; i++)new_state[i][0] = state[i][0] + delta_state[i][0]*lambda;
1227 
1228  GetResiInfo(new_state, &start_step, tmprt, hinfo, tmpresiduals);
1229  double chisq_per_dof = ChiSq(tmpresiduals);
1230 
1231  if(chisq_per_dof<min_chisq_per_dof){
1232  min_chisq_per_dof = chisq_per_dof;
1233  min_lambda = lambda;
1234  }
1235 
1236  // If we're at a lower chi-sq then we're done
1237  if(DEBUG_LEVEL>4)_DBG_<<" -- initial_chisq_per_dof="<<initial_chisq_per_dof<<" new chisq_per_dof="<<chisq_per_dof<<" nhits="<<resiv.GetNrows()<<" p="<<tmprt->swim_steps[0].mom.Mag()<<" lambda="<<lambda<<endl;
1238  if(chisq_per_dof-initial_chisq_per_dof < 0.1 && chisq_per_dof<2.0)break;
1239 
1240  if(chisq_per_dof<initial_chisq_per_dof)break;
1241 
1242  // Chi-sq was increased, try a smaller step on the next iteration
1243  lambda/=2.0;
1244  }
1245  }
1246 
1247  // If we failed to make a step to a smaller chi-sq then signal
1248  // that we were unable to make any improvement.
1249  if(min_lambda==0.0){
1250  if(DEBUG_LEVEL>1)_DBG_<<"Chisq only increased (both directions searched!)"<<endl;
1251  GetResiInfo(rt, hinfo, tmpresiduals);
1252  ChiSq(tmpresiduals, &this->chisq, &this->Ndof); // refill resiv, cov_meas, ...
1253  return kFitNoImprovement;
1254  }
1255 
1256  // Re-create new_state using min_lambda
1257  for(int i=0; i<Nparameters; i++)new_state[i][0] = state[i][0] + delta_state[i][0]*min_lambda;
1258  if(DEBUG_HISTS)this->lambda->Fill(min_lambda);
1259 
1260  // Re-swim reference trajectory using these parameters and re-calc chisq.
1261  // Note that here we have the chisq and Ndof members set.
1262  GetResiInfo(new_state, &start_step, rt, hinfo, tmpresiduals);
1263  ChiSq(tmpresiduals, &this->chisq, &this->Ndof);
1264 
1265  if(DEBUG_LEVEL>3){
1266  DVector3 pos = start_step.origin;
1267  DVector3 mom = start_step.mom;
1268  double phi = mom.Phi();
1269  if(phi<0.0)phi+=2.0*M_PI;
1270  _DBG_<<"LeastSquaresB succeeded: p="<<mom.Mag()<<" theta="<<mom.Theta()<<" phi="<<phi<<" z="<<pos.Z()<<endl;
1271  }
1272 
1273  return kFitSuccess;
1274 }
1275 
1276 //------------------
1277 // FilterGood
1278 //------------------
1279 void DTrackFitterALT1::FilterGood(DMatrix &my_resiv, vector<bool> &my_good, vector<bool> &good_all)
1280 {
1281  /// Remove elements from my_resiv that are not "good" according to the good_all list.
1282  /// The my_good and good_all vectors should be the same size. The number of "true"
1283  /// entries in my_good should be the size of the my_resiv vector. For entries in the
1284  /// my_good vector that are true, but have an entry in good_all that is false, the
1285  /// corresponding entry in my_resiv will be removed. The my_resiv matrix (which should be
1286  /// N x 1) will be resized upon exit. The my_good vector will be set equal to good_all
1287  /// upon exit also so that my_resiv and my_good stay in sync.
1288 
1289  // Make list of rows (and columns) we should keep
1290  vector<int> rows_to_keep;
1291  for(unsigned int i=0, n=0; i<my_good.size(); i++){
1292  if(my_good[i] && good_all[i])rows_to_keep.push_back(n);
1293  if(my_good[i])n++;
1294  }
1295 
1296  // Copy my_resiv to a temporary matrix and resize my_resiv to the new size
1297  int Nrows = (int)rows_to_keep.size();
1298  int Ncols = my_resiv.GetNcols()>1 ? Nrows:1;
1299  DMatrix tmp(my_resiv);
1300  my_resiv.ResizeTo(Nrows, Ncols);
1301 
1302  // Loop over rows and columns copying in the elements we're keeping
1303  for(int i=0; i<Nrows; i++){
1304  int irow = rows_to_keep[i];
1305  for(int j=0; j<Ncols; j++){
1306  int icol = Ncols>1 ? rows_to_keep[j]:0;
1307  my_resiv[i][j] = tmp[irow][icol];
1308  }
1309  }
1310 
1311  my_good = good_all;
1312 }
1313 
1314 //------------------
1315 // PrintChisqElements
1316 //------------------
1317 void DTrackFitterALT1::PrintChisqElements(DMatrix &resiv, DMatrix &cov_meas, DMatrix &cov_muls, DMatrix &weights)
1318 {
1319  /// This is for debugging only.
1320  int Nhits = resiv.GetNrows();
1321  double chisq_diagonal = 0.0;
1322  for(int i=0; i<Nhits; i++){
1323  _DBG_<<" r/sigma "<<i<<": "<<resiv[i][0]*sqrt(weights[i][i])
1324  <<" resi="<<resiv[i][0]
1325  <<" sigma="<<1.0/sqrt(weights[i][i])
1326  <<" cov_meas="<<cov_meas[i][i]
1327  <<" cov_muls="<<cov_muls[i][i]
1328  <<endl;
1329  chisq_diagonal += pow(resiv[i][0], 2.0)*weights[i][i];
1330  }
1331  DMatrix resiv_t(DMatrix::kTransposed, resiv);
1332  DMatrix chisqM(resiv_t*weights*resiv);
1333  int Ndof = Nhits - 5; // assume 5 fit parameters
1334 
1335  _DBG_<<" chisq/Ndof: "<<chisqM[0][0]/(double)Ndof<<" chisq/Ndof diagonal elements only:"<<chisq_diagonal/(double)Ndof<<endl;
1336 }
1337 
1338 //------------------
1339 // ForceLRTruth
1340 //------------------
1342 {
1343  /// This routine is called when the TRKFIT:LR_FORCE_TRUTH parameters is
1344  /// set to a non-zero value (e.g. -PTRKFIT:LR_FORCE_TRUTH=1 is passed
1345  /// on the command line). This is used only for debugging and only with
1346  /// Monte Carlo data.
1347  ///
1348  /// This routine will adjust the left-right choice of each hit based
1349  /// on the current fit track (represented by rt), and the truth information
1350  /// contained in the the DMCTruthPoint objects. It assumes the hits in
1351  /// hinfo correspond to the track represented by rt.
1352 
1353  // Get Truth hits
1354  vector<const DMCTrackHit*> mctrackhits;
1355  loop->Get(mctrackhits);
1356 
1357  // Loop over hits
1358  for(unsigned int i=0; i<hinfo.size(); i++){
1359  hitInfo &hi = hinfo[i];
1360  const DCoordinateSystem *wire = hi.wire;
1361  if(wire==target)continue; // ignore target
1362 
1363  // Sometimes dist is NaN
1364  if(!isfinite(hi.dist)){
1365  hi.err = 100.0;
1366  hi.u_err = 0.0;
1367  continue;
1368  }
1369 
1370  // Find the truth hit corresponding to this real hit
1371  const DMCTrackHit *mctrackhit = DTrackHitSelectorTHROWN::GetMCTrackHit(hi.wire, fabs(hi.dist), mctrackhits, 0);
1372 
1373  // If no truth hit was found, then this may be a noise hit. Set
1374  // the error to something large so it is ignored and warn the
1375  // user.
1376  if(!mctrackhit){
1377  if(DEBUG_LEVEL>1)_DBG_<<"No DMCTrackHit found corresponding to hit "<<i<<" in hinfo! (noise hit?)"<<endl;
1378  hi.err = 100.0;
1379  hi.u_err = 0.0;
1380  continue;
1381  }
1382 
1383  // We do this by looking at the direction of the vector pointing from the
1384  // DOCA point on the wire to that of the fit track and comparing it to
1385  // a similar vector pointing to the truth point. If they both are generally
1386  // in the same direction (small angle) then the fit track is considered
1387  // as being on the correct side of the wire. If they have an angle somewhere
1388  // in the 180 degree range, the fit is considered to be on the wrong side
1389  // of the wire and it is "flipped".
1390  //
1391  // It can also be that the truth vector and the fit vector are at nearly
1392  // a right angle with respect to one another. This really only happens in
1393  // the CDC for tracks going in roughly the same direction as the wire.
1394  // In these cases, the truth point can't help us solve the LR so we set
1395  // the drift distance to zero and give it a larger error so this hit will
1396  // still be included, but appropriately weighted.
1397 
1398  // Vector pointing from wire to the fit track
1399  DVector3 pos_doca, mom_doca;
1400  rt->DistToRT(wire);
1401  rt->GetLastDOCAPoint(pos_doca, mom_doca);
1402  DVector3 shift = wire->udir.Cross(mom_doca);
1403  double u = rt->GetLastDistAlongWire();
1404  DVector3 pos_wire = wire->origin + u*wire->udir;
1405 
1406  // Vector pointing from wire to the truth point
1407  DVector3 pos_truth(mctrackhit->r*cos(mctrackhit->phi), mctrackhit->r*sin(mctrackhit->phi), mctrackhit->z);
1408  DVector3 pos_wire_truth = wire->origin + (pos_truth - wire->origin).Dot(wire->udir)*wire->udir;
1409 
1410  if(DEBUG_LEVEL>8)_DBG_<<" "<<i+1<<": (pos_doca-pos_wire).Angle(pos_truth-pos_wire_truth)="<<(pos_doca-pos_wire).Angle(pos_truth-pos_wire_truth)*57.3<<endl;
1411 
1412  // Decide what to do based on angle between fit and truth vectors
1413  double angle_fit_truth = (pos_doca-pos_wire).Angle(pos_truth-pos_wire_truth);
1414  if(fabs( fabs(angle_fit_truth)-M_PI/2.0) < M_PI/3.0){
1415  // Fit and truth vector are nearly at 90 degrees. Fit this hit
1416  // only to wire position
1417  if(DEBUG_LEVEL>5)_DBG_<<"Downgrading "<<i+1<<"th hit to wire-based (hi.u_err was:"<<hi.u_err<<")"<<endl;
1418  hi.dist = 0.0;
1419  hi.err = 0.35;
1420  hi.u_err = 0.0;
1421  }else{
1422  // Fit and truth vector are nearly (anti)parallel. Decide whether to "flip" hit
1423  if(fabs(angle_fit_truth) > M_PI/2.0){
1424  if(DEBUG_LEVEL>5)_DBG_<<"Flipping side "<<i+1<<"th hit "<<endl;
1425  hi.dist = -hi.dist;
1426  }
1427  }
1428  }
1429 }
1430 
1431 //------------------
1432 // FillDebugHists
1433 //------------------
1435 {
1436  //vertex_mom.SetMagThetaPhi(6.0, 17.2*M_PI/180.0, 90.0*M_PI/180.0);
1437  //vertex_pos.SetXYZ(0.0,0.0,65.0);
1438  //rt->Swim(vertex_pos, vertex_mom);
1439  ptotal->Fill(vertex_mom.Mag());
1440 
1441  // Calculate particle beta
1442  double beta = 1.0/sqrt(1.0+pow(rt->GetMass(), 2.0)/vertex_mom.Mag2()); // assume this is a pion for now. This should eventually come from outer detectors
1443 
1444  for(unsigned int j=0; j<cdchits.size(); j++){
1445  const DCDCTrackHit *hit = cdchits[j];
1446  const DCDCWire *wire = hit->wire;
1447 
1448  // Distance of closest approach for track to wire
1449  double s;
1450  double doca = rt->DistToRT(wire, &s);
1451 
1452  // Distance from drift time. Hardwired for simulation for now
1453  double tof = s/(beta*3E10*1E-9);
1454  double dist = (hit->tdrift-tof)*55E-4;
1455 
1456  // NOTE: Sometimes this could be nan
1457  double resi = dist - doca;
1458  if(!isfinite(resi))continue;
1459 
1460  // Fill histos
1461  residuals_cdc->Fill(resi, wire->ring);
1462  residuals_cdc_vs_s->Fill(resi, wire->ring, s);
1463 
1464  cdcdoca_vs_dist->Fill(dist, doca);
1465  cdcdoca_vs_dist_vs_ring->Fill(dist, doca, wire->ring);
1466  if(wire->stereo==0.0){
1467  dist_axial->Fill(dist);
1468  doca_axial->Fill(doca);
1469  }else{
1470  dist_stereo->Fill(dist);
1471  doca_stereo->Fill(doca);
1472  }
1473 
1474  }
1475 
1476  for(unsigned int j=0; j<fdchits.size(); j++){
1477  const DFDCPseudo *hit = fdchits[j];
1478  const DFDCWire *wire = hit->wire;
1479 
1480  // Distance of closest approach for track to wire
1481  double s;
1482  double doca = rt->DistToRT(wire,&s);
1483 
1484  double tof = s/(beta*3E10*1E-9);
1485  double dist = (hit->time-tof)*55E-4;
1486 
1487  // NOTE: Sometimes this is nan
1488  double resi = dist - doca;
1489  if(isfinite(resi)){
1490  fdcdoca_vs_dist->Fill(dist, doca);
1491  residuals_fdc_anode->Fill(resi, wire->layer);
1492  residuals_fdc_anode_vs_s->Fill(resi, wire->layer,s);
1493  }
1494 
1495  double u = rt->GetLastDistAlongWire();
1496  resi = u - hit->s;
1497  if(isfinite(resi)){
1498  fdcu_vs_s->Fill(u, hit->s);
1499  residuals_fdc_cathode->Fill(resi, wire->layer);
1500  residuals_fdc_cathode_vs_s->Fill(resi, wire->layer,s);
1501  }
1502  }
1503 }
1504 
1505 
#define F(x, y, z)
void setMomentum(const DVector3 &aMomentum)
vector< pull_t > pulls
Definition: DTrackFitter.h:237
DApplication * dapp
const int Ncols
TMatrixD DMatrix
Definition: DMatrix.h:14
double dist
Effective wire shifts due to drift time.
const DCDCWire * wire
Definition: DCDCTrackHit.h:37
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
double u_lorentz
Lorentz correction to u_dist ( u = u_dist + u_lorentz )
const swim_step_t * GetLastSwimStep(void) const
TVector3 DVector3
Definition: DVector3.h:14
Double_t x[NCHANNELS]
Definition: st_tw_resols.C:39
DReferenceTrajectory * tmprt
TH2F * initial_chisq_vs_Npasses
fit_type_t fit_type
Definition: DTrackFitter.h:227
void PrintChisqElements(DMatrix &resiv, DMatrix &cov_meas, DMatrix &cov_muls, DMatrix &weights)
DVector3 GetLastDOCAPoint(void) const
double u_err
Errors on distance along the wire (for FDC cathodes)
void SetMass(double mass)
const DVector3 & position(void) const
const DRootGeom * RootGeom
Definition: DTrackFitter.h:230
void Swim(const DVector3 &pos, const DVector3 &mom, double q=-1000.0, const TMatrixFSym *cov=NULL, double smax=2000.0, const DCoordinateSystem *wire=NULL)
const DFDCWire * wire
DFDCWire for this wire.
Definition: DFDCPseudo.h:92
x-coordinate in RT coordinate system in cm
vector< bool > GetResiInfo(DMatrix &state, const swim_step_t *start_step, DReferenceTrajectory *rt, hitsInfo &hinfo, vector< resiInfo > &residuals)
void FilterGood(DMatrix &my_resiv, vector< bool > &my_good, vector< bool > &good_all)
class DFDCPseudo: definition for a reconstructed point in the FDC
Definition: DFDCPseudo.h:74
double GetLastDistAlongWire(void) const
vector< const DFDCPseudo * > fdchits_used_in_fit
Definition: DTrackFitter.h:242
static const DMCTrackHit * GetMCTrackHit(const DCoordinateSystem *wire, double rdrift, vector< const DMCTrackHit * > &mctrackhits, int trackno_filter=-1)
DReferenceTrajectory * rt
void SetDGeometry(const DGeometry *geom)
swim_step_t * FindClosestSwimStep(const DCoordinateSystem *wire, int *istep_ptr=NULL) const
int layer
1-24
Definition: DFDCWire.h:16
DCoordinateSystem * target
TH3F * residuals_fdc_cathode_vs_s
unsigned int LEAST_SQUARES_MIN_HITS
DTrackFitterALT1(JEventLoop *loop)
void ForceLRTruth(JEventLoop *loop, DReferenceTrajectory *rt, hitsInfo &hinfo)
const DMagneticFieldMap * bfield
Definition: DTrackFitter.h:228
double DistToRT(double x, double y, double z) const
const DCoordinateSystem * wire
Wire definitions.
vector< const DCDCTrackHit * > cdchits
Definition: DTrackFitter.h:224
const DGeometry * geom
Definition: DTrackFitter.h:229
float z
coordinates of hit in cm and rad
Definition: DMCTrackHit.h:20
void SetCheckMaterialBoundaries(bool check_material_boundaries)
z-momentum in RT coordinate system in GeV/c
bool good
Set by GetResiInfo if dist is used.
fit_status_t fit_status
Definition: DTrackFitter.h:240
void GetHits(fit_type_t fit_type, DReferenceTrajectory *rt, hitsInfo &hinfo)
TH3F * cdcdoca_vs_dist_vs_ring
#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
double GetMass(void) const
vector< const DCDCTrackHit * > cdchits_used_in_fit
Definition: DTrackFitter.h:241
void SetDRootGeom(const DRootGeom *RootGeom)
double charge(void) const
fit_status_t FitTrack(void)
position-coordinate in RT coordinate system in cm perpendicular to x both and momentum direction ...
bool good_u
Set by GetResiInfo if u_dist is used.
const swim_step_t * step
x-momentum in RT coordinate system in GeV/c
bool operator()(const T &a, const T &b) const
y-momentum in RT coordinate system in GeV/c
double err
Errors on drift time (or wire position) measurement.
double time
time corresponding to this pseudopoint.
Definition: DFDCPseudo.h:93
void setPID(Particle_t locPID)
DMatrix cov_meas
Measurement errors of hits (diagonal Nmeasurements x Nmeasurements)
double ChiSq(fit_type_t fit_type, DReferenceTrajectory *rt, double *chisq_ptr=NULL, int *dof_ptr=NULL, vector< pull_t > *pulls_ptr=NULL)
double sqrt(double)
vector< const DFDCPseudo * > fdchits
Definition: DTrackFitter.h:225
double sin(double)
DMatrix weights
Inverse of cov_meas + cov_muls.
const DVector3 & momentum(void) const
JEventLoop * loop
Definition: DTrackFitter.h:231
DTrackingData input_params
Definition: DTrackFitter.h:226
TH3F * residuals_fdc_anode_vs_s
double LEAST_SQUARES_MAX_E2NORM
int ring
Definition: DCDCWire.h:80
void SetPLossDirection(direction_t direction)
void setPosition(const DVector3 &aPosition)
vector< hitInfo > hitsInfo
static Particle_t IDTrack(float locCharge, float locMass)
DTrackingData fit_params
Definition: DTrackFitter.h:234
fit_status_t LeastSquaresB(hitsInfo &hinfo, DReferenceTrajectory *rt)
double GetFDCCovariance(int layer1, int layer2)
void FillDebugHists(DReferenceTrajectory *rt, DVector3 &vertex_pos, DVector3 &vertex_mom)
union @6::@8 u
float stereo
Definition: DCDCWire.h:82
double GetCDCCovariance(int layer1, int layer2)
DMatrix cov_muls
Covariance of hits due to multiple scattering (Nmeasurements x Nmeasurements)
double mass(void) const
double u_dist
Distances along the wire (for FDC cathodes)
DMatrix cov_parm
Covariance of fit parameters (Nparms x Nparms (where Nparms=5))
double GetFDCCathodeCovariance(int layer1, int layer2)
DMatrix resiv
residuals vector (Nmeasurements x 1)