QwAnalysis
QwTrackingTreeCombine.cc
Go to the documentation of this file.
1 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
2 /*------------------------------------------------------------------------*//*!
3 
4  \class QwTrackingTreeCombine
5 
6  \brief Combines track segments and performs line fitting.
7 
8  \author Burnham Stokes
9  \date 7/30/08
10 
11  Treecombine performs many of the tasks involved with matching hits to track
12  segments and combining track segments into full tracks with lab coordinates.
13 
14  *//*-------------------------------------------------------------------------*/
15 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
16 
17 #include "QwTrackingTreeCombine.h"
18 
19 // Standard C and C++ headers
20 #include <fstream>
21 #include <cstdio>
22 #include <cmath>
23 #include <cstdlib>
24 #include <cassert>
25 #include <cstring>
26 #include <sys/time.h>
27 #include <algorithm>
28 
29 // Qweak headers
30 #include "QwLog.h"
31 #include "QwOptions.h"
32 #include "QwHitContainer.h"
33 #include "QwDetectorInfo.h"
34 #include "QwTrackingTree.h"
35 #include "QwTreeLine.h"
36 #include "QwPartialTrack.h"
37 #include "QwTrack.h"
38 #include "QwEvent.h"
39 
40 // Qweak headers
41 #include "matrix.h"
42 #include "uv2xy.h"
43 
44 // Qweak tree object headers
45 #include "QwTrackingTreeRegion.h"
46 
47 // Other Qweak modules
48 #include "QwTrackingTreeSort.h"
49 
50 // Minuit2 headers
51 #include <Minuit2/FCNBase.h>
52 #include <Minuit2/MnPrint.h>
53 #include <Math/Functor.h>
54 #include <Fit/Fitter.h>
55 #if ROOT_VERSION_CODE < ROOT_VERSION(5,90,0)
56 #include <TFitterMinuit.h>
57 #endif
58 
59 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
60 
62 : fMaxRoad(0.0),fMaxXRoad(0.0)
63 {
64  fDebug = 0; // Debug level
65 
66  // Get maximum number of HDC planes
67  fMaxMissedPlanes = gQwOptions.GetValue<int>("QwTracking.R2.MaxMissedPlanes");
68  fMaxMissedWires = gQwOptions.GetValue<int>("QwTracking.R3.MaxMissedWires");
69 
70  // Attempt to drop hit with worst residual
71  fDropWorstHit = gQwOptions.GetValue<bool>("QwTracking.R2.DropWorstHit");
72 }
73 
74 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
75 
77 {
78 }
79 
80 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
81 
82 /**
83  * Determines whether the left or right drift distance assignment is closer to
84  * the supplied coordinate for hits in region 3.
85  *
86  * @param track_position Position of the track through this detector plane
87  * @param hit Hit for which we want to resolve the left/right ambiguity
88  * @return Copy of the hit with the selected position
89  */
91  double track_position,
92  QwHit* hit)
93 {
94  // Declarations
95  double position, distance, best_position,best_distance;
96 
97  // First option of left/right ambiguity
98  position = + hit->GetDriftDistance();
99  distance = fabs ( track_position - position );
100  // This is best position for now.
101  best_position = position;
102  best_distance = distance;
103 
104  // Second option of left/right ambiguity
105  position = - hit->GetDriftDistance();
106  distance = fabs ( track_position - position );
107  // Is this a better position?
108  if ( distance < best_distance )
109  best_position = position;
110 
111  // Write the best hit (actually just uses the old structure)
112  QwHit* besthit = new QwHit ( *hit );
113  besthit->fDriftPosition = best_position;
114  return besthit;
115 }
116 
117 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
118 
119 /**
120  * Determines whether the left or right drift distance assignment is closer to
121  * the supplied track coordinate for hits in region 2.
122  *
123  * @param xresult Position of the track crossing through this plane
124  * @param resolution Resolution in this detector plane
125  * @param hitlist Detected hit list (left/right ambiguity not resolved yet)
126  * @param ha Returned hit list (left/right ambiguity is now resolved)
127  * @param Dx Detector offset in the wire plane direction (default value is zero)
128  * @return Number of good hits
129  */
131  double *xresult,
132  double resolution,
133  QwHitContainer *hitlist,
134  QwHit **ha,
135  double Dx )
136 {
137  //###############
138  // DECLARATIONS #
139  //###############
140  int ngood = 0; // number of good hits that have been found already
141  double track_position = *xresult; // x is the x coordinate of the track in the plane
142  double odist = 0.0;
143  double minimum = resolution; // will keep track of minimum distance
144  double wirespacing = hitlist->begin()->GetDetectorInfo()->GetElementSpacing();
145 
146  // Loop over the hit list
147  QwHitContainer::iterator end=hitlist->end();
148  for ( QwHitContainer::iterator hit = hitlist->begin();
149  hit != end; ++hit )
150  {
151  if(hit->GetHitNumber()!=0 || hit->GetDriftDistance()<0) continue;
152  // Consider the two options due to the left/right ambiguity
153  for ( int j = 0; j < 2; ++j )
154  {
155  double hit_position =
156  j ? ( hit->GetElement()-0.5) * wirespacing +
157  hit->GetDriftDistance() + Dx
158  : (hit->GetElement()-0.5)* wirespacing-hit->GetDriftDistance()+Dx;
159  double signed_distance = track_position - hit_position;
160  double distance = fabs ( signed_distance );
161 
162  // Only consider this hit if it is not too far away from the track position,
163  // i.e. within the drift distance resolution
164  if ( distance < resolution )
165  {
166  // Save only a maximum number of hits per track crossing through the plane
167  if ( ngood < MAXHITPERLINE )
168  {
169 
170  // Duplicate this hit for calibration changes
171  ha[ngood] = new QwHit;
172  // Copy the hit, but reset the pointers
173  *ha[ngood] = *hit;
174  // Store this position
175  ha[ngood]->fDriftPosition = hit_position;
176 
177  if ( distance < minimum )
178  {
179  //*xresult = hit_position;
180  minimum = distance;
181  }
182  ++ngood;
183 
184 
185  // If we have already the maximum allowed number of hits,
186  // then save this hit only if it is better than the others
187  }
188  else
189  {
190  // Loop over the hits that we already saved
191  for ( int i = 0; i < ngood; ++i )
192  {
193  distance = track_position - ha[i]->GetDriftPosition();
194  if ( odist < 0 )
195  odist = -odist;
196  if ( distance < odist )
197  {
198  *ha[i] = *hit;
199  ha[i]->fDriftPosition = hit_position;
200  break;
201  }
202  }
203  }
204  } // end of distance cut
205 
206  } // end of left/right ambiguity
207 
208  } // end of loop over hit list
209  return ngood;
210 }
211 
212 
213 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
214 
215 /* --------------------------------------------------------------------------
216  * creates permutations of hits
217  * i : a number from 0 to mul-1 (number of permutation)
218  * mul : the number of permutations
219  * l : the length of r[l], bx[l][MAXHITPERLINE], xa[l]
220  * r : array of multiplicity in detectors
221  * hx : hits filled: ha[l][r[]]
222  * ha : array to write permutated hits in
223  * ------------------------------------------------------------------------- */
225  int i,
226  int mul,
227  int l,
228  int *r,
230  QwHit **ha )
231 {
232  int s;
233 
234  if ( i == 0 )
235  {
236  for ( int j = 0; j < l; j++ )
237  {
238  ha[j] = hx[j][0];
239  }
240  }
241  else
242  {
243  for ( int j = 0; j < l; j++ )
244  {
245  if ( r[j] == 1 )
246  s = 0;
247  else
248  {
249  s = i % r[j];
250  i /= r[j];
251  }
252  ha[j] = hx[j][s];
253  }
254  }
255  return;
256 }
257 
258 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
259 
260 /* ----------------------------------------------------------------------
261  * weight_lsq
262  * we solve the linear equation with
263  *
264  * x = (x_offset, x_slope)
265  * y = (hit positions)
266  * A = - ( (1, zpos1), (1, zpos2), ... )
267  * C = cov(hitpositions)
268  * G = C^-1
269  *
270  * (A^T * G * A) x = -A^T G y
271  *
272  * to do a least square fit weighted with the hit resolutions and
273  * get the covariance matrix for position and slope.
274  */
275 // TODO Why is this similar to weight_lsq_r3? can't this be one function?
277  double& slope, //!< (returns) slope of fitted track
278  double& offset, //!< (returns) offset of fitted track
279  double cov[3], //!< (returns) covariance matrix of slope and offset
280  double& chi, //!< (returns) chi^2 of the fit
281  QwHit **hits, //!< list of hits in every plane
282  int n ) //!< number of planes with hits
283 {
284  // Declaration of matrices
285  double A[n][2], G[n][n], AtGA[2][2];
286  double AtGy[2], y[n], x[2];
287  // Initialize the matrices and vectors
288  for ( int i = 0; i < n; ++i )
289  A[i][0] = -1.0;
290 
291  // Set the hit values
292  for ( int i = 0; i < n; ++i )
293  {
294  A[i][1] = - hits[i]->GetDetectorInfo()->GetZPosition();
295  y[i] = - hits[i]->GetDriftPosition();
296  double resolution = hits[i]->GetDetectorInfo()->GetSpatialResolution();
297  G[i][i] = 1.0 / ( resolution * resolution );
298  }
299 
300  // Calculate right hand side: A^T G y
301  for ( int k = 0; k < 2; ++k )
302  {
303  double sum = 0.0;
304  for ( int i = 0; i < n; i++ )
305  sum += ( A[i][k] ) * G[i][i] * y[i];
306  AtGy[k] = sum;
307  }
308 
309  // Calculate the left hand side: A^T * G * A
310  for ( int j = 0; j < 2; ++j )
311  {
312  for ( int k = 0; k < 2; ++k )
313  {
314  double sum = 0.0;
315  for ( int i = 0; i < n; ++i )
316  sum += ( A[i][j] ) * G[i][i] * A[i][k];
317  AtGA[j][k] = sum;
318  }
319  }
320 
321  // Calculate inverse of A^T * G * A
322  double det = ( AtGA[0][0] * AtGA[1][1] - AtGA[1][0] * AtGA[0][1] );
323  double tmp = AtGA[0][0];
324  AtGA[0][0] = AtGA[1][1] / det;
325  AtGA[1][1] = tmp / det;
326  AtGA[0][1] /= -det;
327  AtGA[1][0] /= -det;
328 
329  // Solve equation: x = (A^T * G * A)^-1 * (A^T * G * y)
330  for ( int k = 0; k < 2; ++k )
331  x[k] = AtGA[k][0] * AtGy[0] + AtGA[k][1] * AtGy[1];
332  slope = x[1];
333  offset = x[0];
334  // Calculate covariance
335  cov[0] = AtGA[0][0];
336  cov[1] = AtGA[0][1];
337  cov[2] = AtGA[1][1];
338 
339  // Calculate chi^2
340  double sum = 0.0;
341  double firstpass=0.0;
342  for ( int i = 0; i < n; ++i )
343  {
344 
345  hits[i]->SetTreeLinePosition(slope * hits[i]->GetDetectorInfo()->GetZPosition() + offset);
346  hits[i]->CalculateTreeLineResidual();
347  double residual = hits[i]->GetTreeLineResidual();
348  firstpass+=fabs(residual);
349  sum += G[i][i] * residual * residual;
350  }
351 
352  // Normalize chi^2
353  chi = sqrt ( sum / (n-2) );
354 
355  firstpass/=n;
356 
357  //the following procedure is used to optimize the treeline by trying to drop one bad hit to see if a significant
358  //improvement of average residual happened. If yes, save it to replace the old one. Now, this optimization is temporarily
359  // turned off.
360  double bad_=0.05;
361  // if all planes got hit or average residual is bigger than 400 microns, then try to minimize the average residual by
362  // dropping one hit from the line
363  if(n==5 && firstpass>bad_){
364 
365  //std::cerr << "happend!" << std::endl;
366  for(int drop=0;drop<4;++drop){
367  for ( int k = 0; k < 2; ++k )
368  {
369  double sum = 0.0;
370  for ( int i = 0; i < n; ++i ){
371  if(i!=drop)
372  sum += ( A[i][k] ) * G[i][i] * y[i];
373  }
374  AtGy[k] = sum;
375  }
376 
377  // Calculate the left hand side: A^T * G * A
378  for ( int j = 0; j < 2; ++j )
379  {
380  for ( int k = 0; k < 2; ++k )
381  {
382  double sum = 0.0;
383  for ( int i = 0; i < n; i++ ){
384  if(i!=drop)
385  sum += ( A[i][j] ) * G[i][i] * A[i][k];
386  }
387  AtGA[j][k] = sum;
388  }
389  }
390 
391  // Calculate inverse of A^T * G * A
392  double det = ( AtGA[0][0] * AtGA[1][1] - AtGA[1][0] * AtGA[0][1] );
393  double tmp = AtGA[0][0];
394  AtGA[0][0] = AtGA[1][1] / det;
395  AtGA[1][1] = tmp / det;
396  AtGA[0][1] /= -det;
397  AtGA[1][0] /= -det;
398 
399  // Solve equation: x = (A^T * G * A)^-1 * (A^T * G * y)
400  for ( int k = 0; k < 2; ++k )
401  x[k] = AtGA[k][0] * AtGy[0] + AtGA[k][1] * AtGy[1];
402  slope = x[1];
403  offset = x[0];
404  // Calculate covariance
405  cov[0] = AtGA[0][0];
406  cov[1] = AtGA[0][1];
407  cov[2] = AtGA[1][1];
408 
409  // Calculate chi^2
410  double sum=0.0;
411 
412  for ( int i = 0; i < n; ++i )
413  {
414  if(i!=drop){
415  hits[i]->SetTreeLinePosition(slope * hits[i]->GetDetectorInfo()->GetZPosition() + offset);
416  hits[i]->CalculateTreeLineResidual();
417  double residual=hits[i]->GetTreeLineResidual();
418  sum += G[i][i] * residual * residual;
419  }
420  }
421 
422  double chi_second=sqrt(sum/(n-3));
423  if(sqrt(chi_second<chi/10)){
424  chi=chi_second;
425  hits[drop]->SetUsed(true);
426  break;
427  }
428  } // the end of the drop loop
429  } // if statement is over
430  // NOTE I have no idea what the next line does, but it also works without this.
431  // It is particularly strange that the corresponding chi_hashfind is never
432  // used: what's the use of writing to a hash list if you never use it?
433  // (wdconinc, July 14, 2009)
434  //chi_hashinsert(hits, n, *slope, *offset, cov, *chi);
435 }
436 
437 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
438 
439 /* ----------------------------------------------------------------------
440  * We solve the linear equation with
441  *
442  * x = (x_offset, x_slope)
443  * y = (hit positions)
444  * A = - ( (1, zpos1), (1, zpos2), ... )
445  * C = cov(hitpositions)
446  * G = C^-1
447  *
448  * (A^T * G * A) x = -A^T G y
449  *
450  * to do a least square fit weighted with the hit resolutions,
451  * and get the covariance matrix for position and slope.
452  */
453 
455  double& slope,
456  double& offset,
457  double cov[3],
458  double& chi,
459  const std::vector<QwHit*> hits,
460  double z1,
461  int wire_offset )
462 {
463  // Return if size is zero, no hits
464  if (hits.size() == 0) return;
465 
466  // Store size
467  size_t n = hits.size();
468 
469  // Declaration of matrices
470  double A[n][2], G[n][n], AtGA[2][2];
471  double AtGy[2], y[n], x[2];
472 
473  // Initialize the matrices and vectors
474  for (size_t i = 0; i < n; i++)
475  A[i][0] = -1.0;
476 
477  //###########
478  // Set Hits #
479  //###########
480  for (size_t i = 0; i < n; i++)
481  {
482  if ( wire_offset == -1 )
483  {
484  A[i][1] = -hits[i]->GetWirePosition(); //used by matchR3 for plane 0
485  y[i] = -hits[i]->GetDriftPosition();
486  }
487  else
488  {
489  //A[i][1] = - ( i + wire_offset ); //used by Tl MatchHits
490  A[i][1] = -hits[i]->GetElement();
491  y[i] = -hits[i]->GetDriftPosition();
492  }
493  double resolution = hits[i]->GetDetectorInfo()->GetSpatialResolution();
494  G[i][i] = 1.0 / ( resolution * resolution );
495  }
496 
497  // Calculate right hand side: -A^T G y
498  for (size_t k = 0; k < 2; k++)
499  {
500  double sum = 0.0;
501  for (size_t i = 0; i < n; i++)
502  sum += A[i][k] * G[i][i] * y[i];
503  AtGy[k] = sum;
504  }
505  // Calculate the left hand side: A^T * G * A
506  for (size_t j = 0; j < 2; j++)
507  {
508  for (size_t k = 0; k < 2; k++)
509  {
510  double sum = 0.0;
511  for (size_t i = 0; i < n; i++)
512  sum += A[i][j] * G[i][i] * A[i][k];
513  AtGA[j][k] = sum;
514  }
515  }
516 
517  // Calculate inverse of A^T * G * A
518  double det = (AtGA[0][0] * AtGA[1][1] - AtGA[1][0] * AtGA[0][1]);
519  double tmp = AtGA[0][0];
520  AtGA[0][0] = AtGA[1][1] / det;
521  AtGA[1][1] = tmp / det;
522  AtGA[0][1] /= -det;
523  AtGA[1][0] /= -det;
524 
525  // Solve equation: x = (A^T * G * A)^-1 * (A^T * G * y)
526  for (size_t k = 0; k < 2; k++)
527  x[k] = AtGA[k][0] * AtGy[0] + AtGA[k][1] * AtGy[1];
528  slope = x[1];
529  offset = x[0];
530  // Calculate covariance
531  cov[0] = AtGA[0][0];
532  cov[1] = AtGA[0][1];
533  cov[2] = AtGA[1][1];
534 
535  // Calculate chi^2
536  double sum = 0.0;
537  if ( wire_offset == -1 )
538  {
539  for (size_t i = 0; i < n; i++)
540  {
541  hits[i]->SetTreeLinePosition ( slope * ( hits[i]->GetWirePosition() - z1 ) + offset );
542  hits[i]->CalculateTreeLineResidual();
543  double residual = hits[i]->GetTreeLineResidual();
544  sum += G[i][i] * residual * residual;
545  }
546  }
547  else
548  {
549  for (size_t i = 0; i < n; i++)
550  {
551  //hits[i]->SetWirePosition ( i + wire_offset ); // TODO element spacing
552  //hits[i]->SetTrackPosition ( slope * ( i + wire_offset ) + offset );
553  hits[i]->SetWirePosition (hits[i]->GetElement());
554  hits[i]->SetTreeLinePosition ( slope * hits[i]->GetElement() + offset );
555  hits[i]->CalculateTreeLineResidual();
556 
557  double residual = hits[i]->GetTreeLineResidual();
558  sum += G[i][i] * residual * residual;
559  }
560  }
561  // Normalize chi^2
562  chi = sqrt ( sum / ( n-2 ) );
563 }
564 
565 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
566 
567 int QwTrackingTreeCombine::contains ( double var, QwHit **arr, int len )
568 {
569  // TODO (wdc) This is unsafe due to double comparisons.
570  // In light of calibration effects, this could fail.
571  cerr << "[QwTrackingTreeCombine::contains] Warning: double == double is unsafe." << endl;
572  for ( int i = 0; i < len ; i++ )
573  {
574  if ( var == arr[i]->GetDriftPosition() )
575  return 1;
576  }
577  return 0;
578 }
579 
580 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
581 
582 /* ------------------------------
583  searches for the closest hit to
584  to *xresult and writes it
585  to *xresult. In addition the
586  hitarray is searched for hits
587  in the detector detect and
588  inbetween *xresult - resolution
589  and *xresult + resolution. All
590  the possible hits are stored
591  in *ha
592 
593  Size of the arrays must be
594  MAXHITPERLINE
595  ------------------------------ */
596 
598  double *xresult,
599  double resolution,
600  QwHit** hitarray,
601  QwHit** ha )
602 {
603  int good = 0;
604  double x = *xresult;
605  double minimum = resolution;
606 
607 
608  for (int num = MAXHITPERLINE * DLAYERS; num-- && *hitarray; hitarray++ )
609  {
610  QwHit* h = *hitarray;
611 
612  // There used to be a functionality with the detector info here. Removed (wdc)
613  // if( !h->GetDetectorInfo() ||
614  // (h->GetDetectorInfo()->GetID() != detec->ID)) {
615  // continue;
616  // }
617 
618  double position = h->GetDriftPosition();
619 
620  if ( ! contains ( position, ha, good ) )
621  {
622  double distance = x - position;
623  ha [good] = h;
624  if ( fabs ( distance ) < minimum )
625  {
626  *xresult = position;
627  minimum = fabs ( distance );
628  }
629  good++;
630  if ( good == MAXHITPERLINE )
631  break;
632  }
633  }
634  return good;
635 }
636 
637 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
638 
639 /*------------------------------------------------------------------------*//*!
640 
641  This method checks whether a track with the given parameters is in the
642  geometric acceptance of all defined detector planes in the specified
643  region and package. Geometric acceptance is calculated from the centers
644  and widths in the geometry definition.
645 
646  Returns one if in the acceptance (or always for region 2), returns zero
647  if not in the acceptance of at least one detector plane.
648 
649  *//*-------------------------------------------------------------------------*/
651  EQwDetectorPackage package,
652  EQwRegionID region,
653  double cx, double mx,
654  double cy, double my )
655 {
656  switch (region) {
657  /* Region 2 */
658  case kRegionID2: {
659  return true;
660  break;
661  }
662 
663  /* Region 3 */
664  case kRegionID3: {
665 
666  // TODO this is of course wrong for tilted planes... hence this
667  // function is not used anywhere (and probably shouldn't exist).
668 
669  // Loop over all direction in this region
670  for ( EQwDirectionID dir = kDirectionU; dir <= kDirectionV; dir++ ) {
671  // Loop over all detector planes
672  double z1 = 0.0;
673  QwGeometry vdc(fGeometry.in(package).in(region).in(dir));
674  for (size_t i = 0; i < vdc.size(); i++) {
675  QwDetectorInfo* det = vdc.at(i);
676  double z = det->GetZPosition();
677  double x = cx + (z - z1) * mx;
678  double y = cy + (z - z1) * my;
679  if (! det->InAcceptance(x,y)) return false;
680  }
681  }
682  break;
683  }
684 
685  /* Others */
686  default: {
687  return true;
688  break;
689  }
690  }
691 
692  return true;
693 }
694 
695 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
696 
697 /*------------------------------------------------------------------------*//*!
698 
699  In TlCheckForX we search for the possible hit assignments for the treeline.
700  While looping over the detector planes, we look at all registered hits and
701  store 'good enough' hits in the goodHits array (indexed by plane number and
702  hit number). Both left and right hits can be stored in goodHits, and a
703  maximum of MAXHITPERLINE hits per detector plane is enforced.
704 
705  Since only one hit per detector plane can be associated with the treeline,
706  we determine the chi^2 for all possible hit permutations. The hit combination
707  with the best chi^2 is stored in the treeline structure.
708 
709  @param x1 position at first plane
710  @param x2 position at last plane
711  @param dx1 uncertainty at first plane
712  @param dx2 uncertainty at last plane
713  @param Dx offset between first and last planes
714  @param z1 reference z coordinate
715  @param Dz distance between first and last planes
716  @param treeline treeline to operate on
717  @param hitlist hit list
718  @param dlayer
719  @param tlayer
720  @param iteration
721  @param stay_tuned
722  @param width
723  *//*-------------------------------------------------------------------------*/
725  double x1, double x2,
726  double dx1, double dx2,
727  double Dx,
728  double z1,
729  double Dz,
730  QwTreeLine *treeline,
731  QwHitContainer *hitlist,
732  int dlayer,
733  int tlayer,
734  int iteration,
735  int stay_tuned,
736  double width )
737 {
738  //################
739  // DECLARATIONS #
740  //################
741  double startZ = 0.0;
742  double endZ = 0.0;
743  std::vector<int> patterns_copy;
744 
745  if ( DLAYERS < 4 ) cerr << "Error: DLAYERS must be >= 4 for region 2!" << endl;
746 
747 
748  // double minweight = 1e10;
749  bool ret = false; /* return value (pessimistic) */
750 
751 
752  // Hit lists (TODO should be QwHitContainer?)
753  QwHit *goodHits[DLAYERS][MAXHITPERLINE]; /* all hits in each detector plane */
754  QwHit *usedHits[DLAYERS]; /* one hit per detector plane */
755 
756  // Initialize to null
757  for ( int i = 0; i < DLAYERS; ++i )
758  {
759  for ( int j = 0; j < MAXHITPERLINE; ++j )
760  {
761  goodHits[i][j] = 0;
762  }
763  patterns_copy.push_back(treeline->fMatchingPattern.at(i));
764  usedHits[i] = 0;
765  }
766 
767  //##################
768  //DEFINE VARIABLES #
769  //##################
770  double orig_slope = (x2 - x1) / Dz; // track slope
771  double orig_dmx = (dx2 - dx1) / Dz; // track resolution slope
772  // (the resolution changes linearly between first and last detector plane)
773 
774  // Bin 'resolution'
775  // TODO This should be retrieved from the QwHitPattern stored inside the tree line
776  int levels = 0;
777  static int levelsR2 = gQwOptions.GetValue<int> ( "QwTracking.R2.levels" );
778  static int levelsR3 = gQwOptions.GetValue<int> ( "QwTracking.R3.levels" );
779  switch ( treeline->GetRegion() )
780  {
781  case kRegionID2: levels = levelsR2; break;
782  case kRegionID3: levels = levelsR3; break;
783  default: break;
784  }
785  double resolution = width / ( 1 << ( levels - 1 ) );
786 
787  //####################################
788  // LOOP OVER DETECTORS IN THE REGION #
789  //####################################
790  // uses BESTX & SELECTX #
791  //###########################
792 
793  // Loop over the detector planes of this package/region/direction
794  int nPlanesWithHits = 0; /* number of detector plane with good hits */
795  int nHitsInPlane[DLAYERS]; /* number of good hits in a detector plane */
796 
797  int nPermutations = 1; /* number of permutations of hit assignments */
798 
799  EQwRegionID region = treeline->GetRegion();
800  EQwDetectorPackage package = treeline->GetPackage();
801  EQwDirectionID dir = treeline->GetDirection();
802 
803  QwGeometry planes(fGeometry.in(package).in(region).in(dir));
804  QwDetectorInfo* front_plane = 0;
805  for (size_t plane = 0; plane < planes.size(); ++plane) {
806 
807  // Get subhitlist of hits in this detector
808  QwHitContainer *hitsInPlane = hitlist->GetSubList_Plane(region, package, planes.at(plane)->GetPlane());
809 
810  // Coordinates of the track at this detector plane
811  double thisZ = planes.at(plane)->GetZPosition();
812  double thisX = orig_slope * (thisZ - z1) + x1;
813 
814  // Store the z coordinates of first detector plane
815  if (! front_plane) {
816  front_plane = planes.at(plane);
817  startZ = thisZ;
818  }
819  // Store the z coordinates of last detector plane
820  endZ = thisZ;
821 
822  // Skip inactive planes
823  if (planes.at(plane)->IsInactive()) {
824  delete hitsInPlane;
825  continue;
826  }
827 
828  // Skip empty planes
829  if (hitsInPlane->size() == 0) {
830  delete hitsInPlane;
831  continue;
832  }
833 
834  /* --- search this road width for hits --- */
835 
836  // resolution at this detector plane
837  double resnow = orig_dmx * (thisZ - z1) + dx1;
838  // unless we override this resolution
839  // NOTE: what is this all about?
840  if (! iteration
841  && ! stay_tuned
842  && plane+1 == planes.size() /* last plane in this set */
843  && tlayer == dlayer)
844  resnow -= resolution * (fMaxRoad - 1.0);
845 
846  // SelectLeftRightHit finds the hits which occur closest to the path
847  // through the first and last detectors:
848  // nHitsInPlane is the number of good hits at each detector layer
849  if (! iteration) { /* first track finding process */
850 
851 
852  double DX_pass=0.0;
853  DX_pass = plane<2 ? 0.0:Dx;
854 
855  nHitsInPlane[nPlanesWithHits] =
856  SelectLeftRightHit(&thisX, resnow, hitsInPlane, goodHits[nPlanesWithHits], DX_pass);
857  }
858 
859  else { /* in iteration process (not used by TlTreeLineSort)*/
860  nHitsInPlane[nPlanesWithHits] =
861  selectx(&thisX, resnow, treeline->fHits, goodHits[nPlanesWithHits]);
862  }
863 
864 
865 
866  /* If there are hits in this detector plane */
867  if ( nHitsInPlane[nPlanesWithHits] ) {
868  nPermutations *= nHitsInPlane[nPlanesWithHits];
869  ++nPlanesWithHits;
870  }
871 
872  // Delete the subhitlist
873  delete hitsInPlane;
874  }
875 
876  // Now the hits that have been found in the road are copied to treeline->hits
877  // This is done by using the temporary pointer hitarray
878  if ( ! iteration ) // return the hits found in SelectLeftRightHit()
879  {
880  QwHit **hitarray = treeline->fHits;
881  for ( int planeWithHits = 0; planeWithHits < nPlanesWithHits; ++planeWithHits )
882  {
883  for ( int hitInPlane = 0; hitInPlane < nHitsInPlane[planeWithHits]; ++hitInPlane )
884  {
885  *hitarray = goodHits[planeWithHits][hitInPlane];
886  // copy hit to new list
887  hitarray++;
888  }
889  }
890 
891  // Check number of hits that have been written and add terminating null
892  if ( hitarray - treeline->fHits < DLAYERS*MAXHITPERLINE + 1 )
893  *hitarray = 0; /* add a terminating 0 for later selectx()*/
894  }
895 
896 
897  //#####################################################
898  // DETERMINE THE BEST SET OF HITS FOR THE TREELINE #
899  //#####################################################
900  // uses : MUL_DO #
901  // WEIGHT_LSQ #
902  //####################
903 
904  // check the validity of goodhits
905 
906 
907  if ( nPlanesWithHits >= dlayer - fMaxMissedPlanes )
908  {
909 
910  // Loop over all possible permutations
911  int best_permutation = -1;
912  double best_slope = 0.0, best_offset = 0.0, best_chi = 1e10;
913  double best_cov[3] = {0.0, 0.0, 0.0};
914  double best_trackpos[4]={0.0};
915  for ( int permutation = 0; permutation < nPermutations; ++permutation )
916  {
917  // Select a permutations from goodHits[][] and store in usedHits[]
918  SelectPermutationOfHits ( permutation, nPermutations, nPlanesWithHits, nHitsInPlane, goodHits, usedHits );
919  // (returns usedHits)
920 
921  // Determine chi^2 of this set of hits
922  double slope, offset; // fitted slope and offset
923  double chi = 0.0; // chi^2 of the fit
924  double cov[3] = {0.0, 0.0, 0.0}; // covariance matrix
925 
926  r2_TreelineFit ( slope, offset, cov, chi, usedHits, nPlanesWithHits );
927  // (returns slope, offset, cov, chi)
928 
929 
930 
931  double stay_chi = 0.0;
932  if ( stay_tuned )
933  {
934  double dh = ( offset + slope * ( startZ - MAGNET_CENTER ) -
935  ( x1 + orig_slope * ( startZ - z1 ) ) );
936  stay_chi += dh * dh;
937  dh = ( offset + slope * ( endZ - MAGNET_CENTER ) -
938  ( x1 + orig_slope * ( endZ - z1 ) ) );
939  stay_chi += dh * dh;
940  }
941  /*
942  if ( stay_chi + chi + dlayer - nPlanesWithHits < minweight )
943  {
944  // has this been the best track so far?
945  minweight = stay_chi + chi + dlayer - nPlanesWithHits;
946  best_chi = chi;
947  best_slope = slope;
948  best_offset = offset;
949  best_permutation = permutation;
950  for(int plane=0;plane<nPlanesWithHits;plane++){
951  best_trackpos[plane]=usedHits[plane]->GetTrackPosition();
952  }
953  */
954 
955  if ( chi < best_chi )
956  {
957  for(int plane=0;plane<nPlanesWithHits;++plane)
958  best_trackpos[plane]=0.0;
959  best_chi = chi;
960  best_slope = slope;
961  best_offset = offset;
962  best_permutation = permutation;
963  for(int plane=0;plane<nPlanesWithHits;++plane){
964  if(!usedHits[plane]->IsUsed())
965  best_trackpos[plane]=usedHits[plane]->GetTreeLinePosition();
966  }
967 
968  memcpy ( best_cov, cov, sizeof cov );
969  }
970 
971  // if the hit is marked as used, we need to reset the used flags as unsed because
972  // this hit will not be used due to the optimization
973  for(int plane=0;plane<nPlanesWithHits;++plane)
974  if(usedHits[plane]->IsUsed())
975  usedHits[plane]->SetUsed(false);
976  }// end of loop over all possible permutations
977 
978 
979 
980  treeline->fOffset = best_offset;
981  treeline->fSlope = best_slope;
982  treeline->fChi = best_chi;
983  treeline->fNumHits = nPlanesWithHits;
984  treeline->SetCov ( best_cov );
985 
986 
987  // Select the best permutation (if it was found)
988  if ( best_permutation != -1 )
989  {
990  SelectPermutationOfHits ( best_permutation, nPermutations,
991  nPlanesWithHits, nHitsInPlane, goodHits, usedHits );
992 
993  for(int plane=0;plane<nPlanesWithHits;++plane){
994  usedHits[plane]->SetTreeLinePosition(best_trackpos[plane]);
995  usedHits[plane]->CalculateTreeLineResidual();
996  }
997 
998  // Reset the used flags
999  for ( int i = 0; i < MAXHITPERLINE * DLAYERS && treeline->fHits[i]; ++i )
1000  treeline->fHits[i]->SetUsed ( false );
1001 
1002  // Set the used flag on all hits that are used in this treeline
1003  for ( int plane = 0; plane < nPlanesWithHits; ++plane )
1004  {
1005  if(best_trackpos[plane]!=0.0){
1006  treeline->AddHit(usedHits[plane]);
1007  if ( usedHits[plane] )
1008  usedHits[plane]->SetUsed ( true );
1009  }
1010  }
1011 
1012  // Store the final set of hits for output
1013  for ( int plane = 0; plane < nPlanesWithHits; ++plane )
1014  {
1015  if ( usedHits[plane] ) treeline->AddHit ( usedHits[plane] );
1016  }
1017  }
1018 
1019  // Set the detector info pointer
1020  if (treeline->fHits[0])
1021  treeline->SetDetectorInfo ( treeline->fHits[0]->GetDetectorInfo() );
1022 
1023  // Check whether we found an optimal track
1024  if ( best_permutation == -1 )
1025  ret = false; // acceptable hit assignment NOT found
1026  else
1027  ret = true; // acceptable hit assignment found
1028 
1029  } // end of if for required number of planes with hits
1030 
1031  // Store the number of planes without hits; if no acceptable hit assignment
1032  // was found, set the treeline to void.
1033  if ( ret )
1034  {
1035  treeline->SetValid();
1036  treeline->fNumMiss = dlayer - nPlanesWithHits;
1037  }
1038  else
1039  {
1040  if ( fDebug )
1041  {
1042  QwDebug << *treeline << "... void because no best hit assignment." << QwLog::endl;
1043  }
1044  treeline->SetVoid();
1045  treeline->fNumMiss = dlayer;
1046  }
1047 
1048  // Return whether an acceptable hit assignment was found
1049  return ret;
1050 }
1051 
1052 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1053 
1054 /* -------------------------------
1055 This function replaces TlCheckForX for region 3. It matches one of
1056 the two wire hits to the hit in the pattern. It then calculates a
1057 chi_square for the matching of the hits to the pattern. This may
1058 be misleading due to the currently low resolution (8 bins) of
1059 the pattern database. It should however, be able to distinguish the
1060 right/left ambiguity for each wire.
1061 
1062 OUTPUT : the best hits are added to treeline's hit list and treeline's
1063  line parameters are set.
1064 --------------------------------*/
1066  double x1, ///< x coordinates at first wire (i.e. distances)
1067  double x2, ///< x coordinates at last wire (i.e. distances)
1068  double z1, ///< z coordinates of first wire (i.e. wire number
1069  double z2, ///< z coordinates of last wire (i.e. wire number)
1070  QwTreeLine *treeline, ///< determined treeline
1071  QwHitContainer *hitlist, ///< hit list
1072  int tlayers ) ///< number of tree layers
1073 {
1074  // This is how region 2 handles this:
1075  //
1076  // // Hit lists
1077  // QwHit *goodHits[tlayers][MAXHITPERLINE]; /* all hits in each wire */
1078  // QwHit *usedHits[tlayers]; /* one hit per wire */
1079  // // Initialize to null
1080  // for (int i = 0; i < DLAYERS; i++) {
1081  // for (int j = 0; j < MAXHITPERLINE; j++) {
1082  // goodHits[i][j] = 0;
1083  // }
1084  // usedHits[i] = 0;
1085  // }
1086 
1087  // Calculate the geometrical parameters of this treeline
1088  // In this function:
1089  // x = signed drift distance to the hit wire
1090  // z = wire number 'coordinate' (starting at wire 0)
1091  double dx = x2 - x1;
1092  double dz = z2 - z1;
1093  double track_slope = dx / dz;
1094  // Distance to wire at (theoretical) wire 0
1095  double intercept = x1 - track_slope * z1;
1096  // Number of wires that can possibly be hit for this treeline
1097  int nWires = abs ( treeline->fR3LastWire - treeline->fR3FirstWire + 1 );
1098 
1099 
1100  // Loop over the hits with wires in this tree line
1101  int nHits = 0;
1102 
1103  int tl_first = treeline->fR3Offset+treeline->fR3FirstWire;
1104  int tl_last = treeline->fR3Offset+treeline->fR3LastWire;
1105 
1106  // Keep track of crosstalk wires
1107  std::vector<size_t> crosstalk_hits;
1108 
1109  for (QwHitContainer::iterator hit = hitlist->begin();
1110  hit != hitlist->end() && nHits < tlayers; hit++ )
1111  {
1112  // int begin=0,end=0;
1113  // double track_resolution=hit->GetDetectorInfo()->GetTrackResolution();
1114  // double halfwidth=1.52;
1115  int wire = hit->GetElement();
1116 
1117  if (wire < tl_first || wire > tl_last) {
1118  continue;
1119  }
1120 
1121  if (hit->IsUsed() == false)
1122  continue;
1123 
1124  // if ( wire < (tl_first - fMaxMissedWires+2)
1125  // || wire > (tl_last + fMaxMissedWires-2)
1126  // || hit->GetHitNumber() != 0 )
1127  // continue;
1128  //
1129  // if(wire < tl_first){
1130  // begin=(halfwidth-hit->GetDriftDistance()-track_resolution)/halfwidth*4;
1131  // if(begin > treeline->a_beg) continue;
1132  // }
1133  // else if( wire > tl_last){
1134  // end=(halfwidth+hit->GetDriftDistance()+track_resolution)/halfwidth*4;
1135  // if(end < treeline->b_end) continue;
1136  // }
1137 
1138  // Calculate the wire number and associated z coordinate
1139  double thisZ = ( double ) hit->GetElement();
1140  // Calculate the track position at this wire
1141  double thisX = track_slope * thisZ + intercept;
1142 
1143  // Determine the best hit assignment for this position
1144  QwHit* goodhit = SelectLeftRightHit ( thisX, & ( *hit ));
1145 
1146  //############################
1147  //RETURN HITS FOUND IN BESTX #
1148  //############################
1149 
1150  goodhit->SetUsed ( true );
1151  treeline->AddHit(goodhit);
1152  // increment counter
1153  nHits++;
1154 
1155  // Delete the hit from SelectLeftRightHit again so as to not leak memory
1156  delete goodhit;
1157 
1158 
1159  // Check whether this wire in this detector is affected by crosstalk
1160  int wire2 = hit->GetDetectorInfo()->GetCrosstalkElement(wire);
1161  if (wire2 > 0) {
1162  QwVerbose << "Potential crosstalk: wire " << wire << " with " << wire2
1163  << " in det " << hit->GetDetectorInfo()->GetDetectorName() << QwLog::endl;
1164  crosstalk_hits.push_back(treeline->GetNumberOfHits()-1);
1165  }
1166  }
1167 
1168  // Warn when the number of wires between first and last is different from the
1169  // number of hits found (missing wires or wires wit multiple hits)
1170  // if ( nHits != nWires )
1171  // QwWarning << "Expected " << nWires << " consecutive wires to be hit, " << "but found " << nHits << " hits in plane" << treeline->GetPlane() << QwLog::endl;
1172 
1173  // Return if no hits were found
1174  //if (nHits == 0) return 0;
1175 
1176  //######################
1177  //CALCULATE CHI SQUARE #
1178  //######################
1179  double chi = 0.0;
1180  double slope = 0.0, offset = 0.0;
1181  double cov[3] = {0.0, 0.0, 0.0};
1182  r3_TreelineFit(slope, offset, cov, chi, treeline->GetListOfHits(), z1, treeline->fR3Offset);
1183 
1184  //################
1185  //SET PARAMETERS #
1186  //################
1187  treeline->SetOffset(offset);
1188  treeline->SetSlope(slope);
1189  treeline->SetChi(chi);
1190  treeline->SetCov(cov);
1191  treeline->fNumHits = nHits;
1192 
1193  // Set the detector info pointer
1194  treeline->SetDetectorInfo(treeline->GetHit(0)->GetDetectorInfo());
1195 
1196  //####################
1197  //DEAL WITH CROSSTALK#
1198  //####################
1199 
1200  // When there was a possibility for crosstalk in this treeline
1201  if (crosstalk_hits.size() > 0) {
1202 
1203  // Keep vector of indices to delete later
1204  std::vector<size_t> delete_hits;
1205 
1206  // Loop over all crosstalk hits
1207  for (size_t i1 = 0; i1 < crosstalk_hits.size(); i1++) {
1208  const QwHit* hit1 = treeline->GetHit(crosstalk_hits.at(i1));
1209  const QwDetectorInfo* det1 = hit1->GetDetectorInfo();
1210  int wire1 = hit1->GetElement();
1211  int wire1_crosstalk = det1->GetCrosstalkElement(wire1);
1212 
1213  // Loop over remaining crosstalk hits
1214  for (size_t i2 = i1+1; i2 < crosstalk_hits.size(); i2++) {
1215  const QwHit* hit2 = treeline->GetHit(crosstalk_hits.at(i2));
1216  const QwDetectorInfo* det2 = hit2->GetDetectorInfo();
1217  int wire2 = hit2->GetElement();
1218  int wire2_crosstalk = det2->GetCrosstalkElement(wire2);
1219 
1220  // If crosstalk wires match
1221  if (wire1 == wire2_crosstalk && wire2 == wire1_crosstalk) {
1222 
1223  // Get treeline residuals
1224  double res1 = hit1->GetTreeLineResidual();
1225  double res2 = hit2->GetTreeLineResidual();
1226  QwVerbose << "Crosstalk: "
1227  << "wire1 " << wire1 << " res1 = " << res1 << " cm, "
1228  << "wire2 " << wire2 << " res2 = " << res2 << " cm"
1229  << QwLog::endl;
1230 
1231  // Mark the hit with highest residual for deletion
1232  if (res1 > res2) {
1233  QwVerbose << "Will delete hit " << crosstalk_hits.at(i1)
1234  << " wire "
1235  << treeline->GetHit(crosstalk_hits.at(i1))->GetElement()
1236  << QwLog::endl;
1237  delete_hits.push_back(crosstalk_hits.at(i1));
1238  // skip this i1 hit by skipping all other i2 hits
1239  i2 = crosstalk_hits.size();
1240  } else {
1241  QwVerbose << "Will delete hit " << crosstalk_hits.at(i2)
1242  << " wire "
1243  << treeline->GetHit(crosstalk_hits.at(i2))->GetElement()
1244  << QwLog::endl;
1245  delete_hits.push_back(crosstalk_hits.at(i2));
1246  }
1247  }
1248  }
1249  }
1250 
1251  // Print original treeline
1252  QwVerbose << "Original " << *treeline << QwLog::endl;
1253 
1254  // Delete the hits marked for deletion:
1255  // but because the vector delete_hits can contain equal indices, we must
1256  // be careful when deleting. We sort the indices to delete, then run them
1257  // through unique, and then resize the vector to only include the sorted
1258  // unique indices. Now we can delete from the end.
1259  std::sort(delete_hits.begin(), delete_hits.end());
1260  std::vector<size_t>::iterator uniques_end =
1261  std::unique(delete_hits.begin(), delete_hits.end());
1262  delete_hits.resize(std::distance(delete_hits.begin(),uniques_end));
1263  for (int i = delete_hits.size() - 1; i >= 0; i--) { // signed int because of i >= 0
1264  QwVerbose << "Deleting hit " << delete_hits.at(i)
1265  << " wire "
1266  << treeline->GetHit(delete_hits.at(i))->GetElement()
1267  << " with res "
1268  << treeline->GetHit(delete_hits.at(i))->GetTreeLineResidual()
1269  << QwLog::endl;
1270  treeline->DeleteHit(delete_hits.at(i));
1271  }
1272 
1273  // Redo the fit
1274  r3_TreelineFit(slope, offset, cov, chi, treeline->GetListOfHits(), z1, treeline->fR3Offset);
1275  treeline->SetOffset(offset);
1276  treeline->SetSlope(slope);
1277  treeline->SetChi(chi);
1278  treeline->SetCov(cov);
1279 
1280  // Print updated treeline
1281  QwVerbose << "Updated " << *treeline << QwLog::endl;
1282  }
1283 
1284  //################
1285  //SET PARAMETERS #
1286  //################
1287  treeline->SetOffset(offset);
1288  treeline->SetSlope(slope);
1289  treeline->SetChi(chi);
1290  treeline->SetCov(cov);
1291  treeline->fNumHits = nHits;
1292 
1293  // Set the detector info pointer
1294  treeline->SetDetectorInfo(treeline->GetHit(0)->GetDetectorInfo());
1295 
1296  int ret = 1; //need to set up a check that the missing hits is not greater than 1.
1297  if ( ! ret )
1298  {
1299  treeline->SetVoid();
1300  treeline->fNumMiss = nWires - nHits;
1301  }
1302  else
1303  {
1304  QwDebug << "Treeline: voided because no best hit assignment" << QwLog::endl;
1305  QwDebug << "...well, actually this hasn't been implemented properly yet." << QwLog::endl;
1306  treeline->SetValid();
1307  treeline->fNumMiss = nWires - nHits;
1308  }
1309  return ret;
1310 }
1311 
1312 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1313 
1314 /* ------------------------------
1315  Marks TreeLines close to
1316  other Lines as being good
1317  or bad in respect to their
1318  chi^2
1319  ------------------------------ */
1321  QwTreeLine *treelinelist,
1322  QwHitContainer *hitlist,
1323  EQwDetectorPackage package,
1324  EQwRegionID region,
1325  EQwDirectionID dir,
1326  unsigned long bins,
1327  int tlayer,
1328  int dlayer,
1329  double width )
1330 {
1331  switch (region) {
1332  /* Region 3 */
1333  case kRegionID3: {
1334 
1335  /* TODO In this section we should replace the treeline list with an
1336  std::list<QwTreeLine>. */
1337 
1338  /* --------------------------------------------------
1339  Calculate line parameters first
1340  -------------------------------------------------- */
1341 
1342  // For each valid tree line
1343  for ( QwTreeLine *treeline = treelinelist;
1344  treeline && treeline->IsValid();
1345  treeline = treeline->next )
1346  {
1347  // First wire position
1348  double z1 = ( double ) ( treeline->fR3Offset + treeline->fR3FirstWire );
1349  // Last wire position
1350  double z2 = ( double ) ( treeline->fR3Offset + treeline->fR3LastWire );
1351 
1352  double d1 = 0, d2 = 0;
1353  int oct=0;
1354  for (QwHitContainer::iterator hit = hitlist->begin(); hit != hitlist->end(); hit++) {
1355  int wire = hit->GetElement();
1356  int row = wire-treeline->fR3Offset;
1357  if(oct==0 && hit->GetDetectorInfo()->GetPackage() == package){
1358  oct=hit->GetDetectorInfo()->GetOctant();
1359  }
1360  if (row < 0 || row > 7) continue;
1361  double distance = hit->GetDriftDistance();
1362  double track_resolution=hit->GetDetectorInfo()->GetTrackResolution();
1363  std::pair<double,double> range = treeline->CalculateDistance(row,width,bins,track_resolution);
1364  if (distance >= range.first && distance <= range.second) {
1365  hit->SetUsed(true);
1366  }
1367  if (wire == z1 && hit->IsUsed())
1368  d1 = distance;
1369  else if (wire == z2 && hit->IsUsed())
1370  d2 = distance;
1371  }
1372 
1373  d1 *= -1;
1374 
1375 
1376  // Bin width (bins in the direction of chamber thickness)
1377  // double dx = width / ( double ) bins;
1378  // Chamber thickness coordinates at first and last wire
1379 
1380  // double x1 = ( treeline->a_beg - ( double ) bins/2 ) * dx + dx/2;
1381  // double x2 = ( treeline->b_end - ( double ) bins/2 ) * dx + dx/2;
1382 
1383  treeline->SetOctant(oct);
1384  // Match the hits with the correct treeline
1385  TlMatchHits (
1386  d1, d2, z1, z2,
1387  treeline, hitlist,
1388  MAX_LAYERS );
1389  }
1390  break;
1391  }
1392 
1393  /* Region 2 */
1394  case kRegionID2: {
1395 
1396  // Get the front and back HDC plane to determine offset
1397  QwGeometry hdc(fGeometry.in(package).in(region).in(dir));
1398  QwDetectorInfo* front = hdc.front();
1399  QwDetectorInfo* back = hdc.back();
1400  // double r1 = front->GetYPosition();
1401  double z1 = front->GetZPosition();
1402  // double r2 = back->GetYPosition();
1403  double z2 = back->GetZPosition();
1404  //double rcos = back->GetElementAngleCos();
1405  assert(front->GetOctant()==back->GetOctant());
1406 
1407  // We are looping over detectors with the same direction
1408  // double Dr = (r2 - r1); // difference in r position
1409  double Dz = (z2 - z1); // difference in z position
1410  //double Dx = Dr * fabs (rcos); // difference in x position
1411  double Dx=back->GetPlaneOffset()-front->GetPlaneOffset();
1412  //std::cout << "position difference first/last: " << Dx << " cm" << std::endl;
1413  QwDebug << "position difference first/last: " << Dx << " cm" << QwLog::endl;
1414 
1415  // Determine bin widths
1416  double dx = width; // detector width
1417  //double dxh = 0.5 * dx; // detector half-width
1418  dx /= ( double ) bins; // width of each bin
1419  //double dxb = dxh / (double) bins; // half-width of each bin
1420 
1421  /* --------------------------------------------------
1422  calculate line parameters first
1423  -------------------------------------------------- */
1424 
1425  // Loop over all valid tree lines
1426  for ( QwTreeLine *treeline = treelinelist;
1427  treeline; treeline = treeline->next )
1428  {
1429  if ( treeline->IsVoid() )
1430  {
1431  // No tree lines should be void yet
1432  QwWarning << "Warning: No tree lines should have been voided yet!" << QwLog::endl;
1433  continue;
1434  }
1435 
1436  treeline->SetOctant(front->GetOctant());
1437  // Debug output
1438  QwDebug << *treeline << QwLog::endl;
1439 
1440  // Calculate the track from the average of the bins that were hit
1441 
1442  double x1 = treeline->GetPositionFirst ( dx );
1443  double x2 = treeline->GetPositionLast ( dx ) + Dx;
1444  // Calculate the uncertainty on the track from the differences
1445  // and add a road width in units of bin widths
1446 
1447  double dx1 = treeline->GetResolutionFirst ( dx ) + dx * fMaxRoad;
1448  double dx2 = treeline->GetResolutionLast ( dx ) + dx * fMaxRoad;
1449 
1450  // Debug output
1451  QwDebug << "(x1,x2,z1,z2) = (" << x1 << ", " << x2 << ", " << z1 << ", " << z2 << "); " << QwLog::endl;
1452  QwDebug << "(dx1,dx2) = (" << dx1 << ", " << dx2 << ")" << QwLog::endl;
1453 
1454  // Check this tree line for hits and calculate chi^2
1455  TlCheckForX (
1456  x1, x2, dx1, dx2, Dx, z1, Dz,
1457  treeline, hitlist,
1458  tlayer, tlayer, 0, 0, width );
1459 
1460  // Debug output
1461  QwDebug << "Done processing " << *treeline << QwLog::endl;
1462  }
1463  break;
1464  }
1465  /* Other regions */
1466  default:
1467  QwWarning << "Warning: TreeCombine not implemented for region " << region << QwLog::endl;
1468  }
1469  /* End of region-specific parts */
1470 
1471 
1472  // Calculate the average residual
1473  for (QwTreeLine *treeline = treelinelist; treeline;
1474  treeline = treeline->next) {
1475  if (treeline->IsValid()) {
1476  treeline->CalculateAverageResidual();
1477  }
1478  }
1479 
1480  // Now search for identical tree lines in the list
1481  QwDebug << "Searching for identical treelines..." << QwLog::endl;
1482  for (QwTreeLine *treeline1 = treelinelist; treeline1;
1483  treeline1 = treeline1->next) {
1484  if (treeline1->IsValid()) {
1485  for (QwTreeLine *treeline2 = treeline1->next; treeline2;
1486  treeline2 = treeline2->next) {
1487  if (treeline2->IsValid()
1488  && treeline1->fOffset == treeline2->fOffset
1489  && treeline1->fSlope == treeline2->fSlope) {
1490  QwDebug << *treeline2 << "... ";
1491  QwDebug << "void because it already exists." << QwLog::endl;
1492  treeline2->SetVoid();
1493  } // end of second treeline valid and equal to first treeline
1494  } // end of second loop over treelines
1495  } // end of first treeline valid
1496  } // end of first loop over treelines
1497  // Print the list of tree lines
1498  if (fDebug) {
1499  cout << "List of treelines:" << endl;
1500  if (treelinelist) treelinelist->Print();
1501  }
1502 }
1503 
1504 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1505 /*!--------------------------------------------------------------------------*\
1506  Minuit2 Set-up
1507  The following is the code that the minuit2 minimizer calls in
1508  r2_PartialTrackFit to optimize the fit parameters. It applies
1509  rotation parameters defined in the geofile (qweak_HDC.<runrange>.geo)
1510  found in the QwAnalysis/Tracking/src/ directory. These rotation
1511  parameters (defined by plane) allow the individual planes in Region 2
1512  to be rotated around the center of each chamber. **this eventually needs
1513  to be corrected to have both chambers in a package rotate around the same
1514  point**
1515  *//*-------------------------------------------------------------------------*/
1516 
1517 class MyFCN : public ROOT::Minuit2::FCNBase {
1518 
1519  public:
1520 
1521  MyFCN(std::vector<QwHit*> fhits) : hits(fhits) {}
1522 
1523  double operator() (const double* array) const {
1524  const std::vector<double> fit(array, array + 4);
1525  return operator()(fit);
1526  }
1527 
1528  double operator() (const std::vector<double> & fit) const {
1529  double value = 0;
1530  double chi2 = 0;
1531  double resolution = hits[0]->GetDetectorInfo()->GetSpatialResolution();
1532  double normalization = 1/(resolution*resolution);
1533 
1534 
1535  // Calculate the metric matrix
1536  double dx_[12] = { 0.0 };
1537  double l[3] = { 0.0 };
1538  double h[3] = { 0.0 };
1539  for (size_t i = 0; i < hits.size(); ++i)
1540  dx_[hits[i]->GetPlane() - 1] = hits[i]->GetDetectorInfo()->GetPlaneOffset();
1541 
1542  for (size_t i = 0; i < 3; ++i)
1543  {
1544  h[i] = dx_[6 + i] == 0 ? dx_[9 + i] : dx_[6 + i];
1545  l[i] = dx_[i] == 0 ? dx_[3 + i] : dx_[i];
1546  dx_[i] = dx_[3 + i] = 0;
1547  dx_[6 + i] = dx_[9 + i] = h[i] - l[i];
1548  }
1549 
1550  for (size_t i=0; i<hits.size();i++)
1551  {
1552 
1553  double cosx = hits[i]->GetDetectorInfo()->GetDetectorRollCos();
1554  double sinx = hits[i]->GetDetectorInfo()->GetDetectorRollSin();
1555  double cosy = hits[i]->GetDetectorInfo()->GetDetectorPitchCos();
1556  double siny = hits[i]->GetDetectorInfo()->GetDetectorPitchSin();
1557  double rcos = hits[i]->GetDetectorInfo()->GetElementAngleCos();
1558  double rsin = hits[i]->GetDetectorInfo()->GetElementAngleSin();
1559 
1560  double dx = dx_[hits[i]->GetPlane() - 1];
1561 
1562  double wire_off = -0.5 * hits[i]->GetDetectorInfo()->GetElementSpacing()
1563  + hits[i]->GetDetectorInfo()->GetElementOffset();
1564  double hit_pos = hits[i]->GetDriftPosition() + wire_off - dx;
1565 
1566  // Get end points of the hit wire
1567  double x0 = hit_pos/rsin;
1568  double y0 = hit_pos/rcos;
1569 
1570  double zRot = 1e6;
1571  if(hits[i]->GetPackage()==1) zRot = -315.9965;
1572  if(hits[i]->GetPackage()==2) zRot = -315.33;
1573 
1574  double z0 = hits[i]->GetDetectorInfo()->GetZPosition();
1575  double zD = z0 - zRot;
1576 
1577  double xR_1 = x0;
1578  double yR_1 = 0.0;
1579  double zR_1 = z0;
1580  double xR_2 = 0.0;
1581  double yR_2 = y0;
1582  double zR_2 = z0;
1583 
1584  xR_1 = cosy*x0 +zD*cosx*siny;
1585  yR_1 = zD*sinx;
1586  zR_1 = zD*cosx*cosy + zRot - siny*x0;
1587 
1588  xR_2 = zD*cosx*siny - siny*sinx*y0;
1589  yR_2 = cosx*y0 + zD*sinx;
1590  zR_2 = zD*cosx*cosy + zRot - sinx*cosy*y0;
1591 
1592  double xc = hits[i]->GetDetectorInfo()->GetXPosition();
1593  double yc = hits[i]->GetDetectorInfo()->GetYPosition();
1594 
1595  double z = (-(fit[1]-xc-zD*cosx*siny)*cosx*siny -
1596  (fit[3]-yc-zD*sinx)*sinx*(cosy*cosy-siny*siny) +
1597  (zRot + zD*cosx*cosy)*cosy*cosx) /
1598  (fit[0]*cosx*siny + fit[2]*sinx*(cosy*cosy-siny*siny) + cosy*cosx);
1599 
1600  double x = fit[1] + fit[0] * z;
1601  double y = fit[3] + fit[2] * z;
1602 
1603 
1604  x -= xc;
1605  y -= yc;
1606 
1607  double diffx = xR_2 - xR_1;
1608  double diffy = yR_2 - yR_1;
1609  double diffz = zR_2 - zR_1;
1610 
1611  double numx = -y*diffz + z*diffy + yR_1*zR_2 - yR_2*zR_1;
1612  double numy = x*diffz - z*diffx - xR_1*zR_2 + xR_2*zR_1;
1613  double numz = -x*diffy + y*diffx + xR_1*yR_2 - xR_2*yR_1;
1614 
1615  double num = sqrt(numx*numx + numy*numy + numz*numz);
1616 
1617  double demx = xR_2 - xR_1;
1618  double demy = yR_2 - yR_1;
1619  double demz = zR_2 - zR_1;
1620  double dem = sqrt(demx*demx + demy*demy + demz*demz);
1621 
1622  double residual = num / dem;
1623 
1624  chi2 += normalization * residual * residual;
1625  }
1626  chi2 /= (hits.size() - 4);
1627  return chi2;
1628 
1629 
1630  }
1631 
1632 
1633  double Up() const { return 1.; }
1634 
1635 
1636 
1637  private:
1638 
1639  std::vector<QwHit*> hits;
1640 };
1641 
1642 
1643 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
1644 /*!--------------------------------------------------------------------------*\
1645 
1646  r2_TrackFit()
1647 
1648  This function fits a set of hits in the HDC to a 3-D track. This
1649  task is complicated by the unorthogonality of the u,v, and x wire
1650  planes. To obtain the track, the metric matrix (defined below) is
1651  calculated using the projections of each hit into the lab
1652  coordinate system. The matrix is inverted in order to solve the
1653  system of four equations for the four unknown track parameters
1654  (bx,mx,by,my). Once the fit is calculated, the chisquare value
1655  is determined so that this track may be compared to other track
1656  candidates in order to select the best fit.
1657 
1658  metric matrix : The metric matrix is defined by the chi-squared
1659  equation for unorthogonal coordinate systems. In order to
1660  solve for the four track parameters, chi-square is
1661  differentiated with respect to the parameters, and set to
1662  zero. The metric matrix is then derived from the four
1663  equations using the standard linear algebra technique for
1664  solving systems of equations.
1665 
1666  *//*-------------------------------------------------------------------------*/
1667 
1669  const int num_hits,
1670  QwHit **hits,
1671  double *fit,
1672  double *cov,
1673  double &chi2,
1674  double* signedresidual,
1675  bool drop_worst_hit)
1676 {
1677  //##################
1678  // Initializations #
1679  //##################
1680 
1681  // Initialize the matrices
1682  double A[4][4];
1683  double *Ap = &A[0][0];
1684  double B[4];
1685  for (int i = 0; i < 4; ++i)
1686  {
1687  B[i] = 0.0;
1688  for (int j = 0; j < 4; ++j)
1689  A[i][j] = 0.0;
1690  }
1691 
1692  // Find first hit on a X wire
1693  int hitx = 0; // will be number of X hits
1694  for (hitx = 0; hitx < num_hits; ++hitx)
1695  if (hits[hitx]->GetDetectorInfo()->GetElementDirection() == kDirectionX)
1696  break;
1697  // Find first hit on a U wire
1698  int hitu = 0; // will be number of U hits
1699  for (hitu = 0; hitu < num_hits; ++hitu)
1700  if (hits[hitu]->GetDetectorInfo()->GetElementDirection() == kDirectionU)
1701  break;
1702  // Find first hit on a V wire
1703  int hitv = 0; // will be number of V hits
1704  for (hitv = 0; hitv < num_hits; ++hitv)
1705  if (hits[hitv]->GetDetectorInfo()->GetElementDirection() == kDirectionV)
1706  break;
1707 
1708  // Did we have any direction without any hits? i.e. first hit is identical to number of hits
1709  if (hitx == num_hits || hitu == num_hits || hitv == num_hits) {
1710  QwWarning << "No hit on X plane found. What I gotta do?" << QwLog::endl;
1711  return -1;
1712  }
1713 
1714  // Calculate the metric matrix
1715  double dx_[12] = { 0.0 };
1716  double l[3] = { 0.0 };
1717  double h[3] = { 0.0 };
1718  for (int i = 0; i < num_hits; ++i)
1719  dx_[hits[i]->GetPlane() - 1] = hits[i]->GetDetectorInfo()->GetPlaneOffset();
1720 
1721  //dx_ is used to save the Dx for every detector
1722  for (int i = 0; i < 3; ++i)
1723  {
1724  h[i] = dx_[6 + i] == 0 ? dx_[9 + i] : dx_[6 + i];
1725  l[i] = dx_[i] == 0 ? dx_[3 + i] : dx_[i];
1726  dx_[i] = dx_[3 + i] = 0;
1727  dx_[6 + i] = dx_[9 + i] = h[i] - l[i];
1728  }
1729 
1730  for (int i = 0; i < num_hits; ++i)
1731  {
1732  // Normalization = 1/sigma^2
1733  double resolution = hits[i]->GetDetectorInfo()->GetSpatialResolution();
1734  double normalization = 1.0 / (resolution * resolution);
1735 
1736  // Get cos and sin of the wire angles of this plane
1737  double rcos = hits[i]->GetDetectorInfo()->GetElementAngleCos();
1738  double rsin = hits[i]->GetDetectorInfo()->GetElementAngleSin();
1739 
1740  // Determine the offset of the center of this plane
1741  double center_x = hits[i]->GetDetectorInfo()->GetXPosition();
1742  double center_y = hits[i]->GetDetectorInfo()->GetYPosition();
1743  double center_offset = rcos * center_y + rsin * center_x;
1744 
1745  // TODO
1746  double dx = dx_[hits[i]->GetPlane() - 1];
1747 
1748  double wire_off = -0.5 * hits[i]->GetDetectorInfo()->GetElementSpacing()
1749  + hits[i]->GetDetectorInfo()->GetElementOffset();
1750  double hit_pos = hits[i]->GetDriftPosition() + wire_off - dx;
1751 
1752  double r[4];
1753  r[0] = rsin;
1754  r[1] = rsin * (hits[i]->GetDetectorInfo()->GetZPosition());
1755  r[2] = rcos;
1756  r[3] = rcos * (hits[i]->GetDetectorInfo()->GetZPosition());
1757  for (int k = 0; k < 4; ++k)
1758  {
1759  B[k] += normalization * r[k] * (hit_pos + center_offset);
1760  for (int j = 0; j < 4; ++j)
1761  A[k][j] += normalization * r[k] * r[j];
1762  }
1763  }
1764 
1765  // Invert the metric matrix
1766  M_Invert(Ap, cov, 4);
1767 
1768  // Check that inversion was successful
1769  if (!cov)
1770  {
1771  QwWarning << "Inversion failed" << QwLog::endl;
1772  return -1;
1773  }
1774 
1775  // Calculate the fit
1776  M_A_times_b(fit, cov, 4, 4, B); // fit = matrix cov * vector B
1777 
1778  // Calculate chi2^2,rewrite
1779  chi2 = 0.0;
1780  std::pair<int, double> worst_case(0, -0.01);
1781 
1782  // Fit function
1783  std::vector<QwHit*> test;
1784  for (int i = 0; i < num_hits; ++i)
1785  test.push_back(hits[i]);
1786  // Load into object with operator()
1787  MyFCN *fcn = new MyFCN(test);
1788 
1789 #if ROOT_VERSION_CODE < ROOT_VERSION(5,90,0)
1790 
1791  //Call the Minuit2 code to minimize chi2
1792  TFitterMinuit minuit;
1793  minuit.SetPrintLevel(fDebug-1);
1794  minuit.SetMinuitFCN(fcn);
1795  minuit.SetParameter(0,"M", fit[1],1,0,0);
1796  minuit.SetParameter(1,"XOff",fit[0],100,0,0);
1797  minuit.SetParameter(2,"N", fit[3],1,0,0);
1798  minuit.SetParameter(3,"YOff",fit[2],100,0,0);
1799  minuit.CreateMinimizer();
1800  int iret = minuit.Minimize();
1801  if (iret != 0) QwVerbose << "Minuit: old fit failed! " << iret << QwLog::endl;
1802 
1803  std::vector<double> oldpars;
1804  oldpars.push_back(minuit.GetParameter(0));
1805  oldpars.push_back(minuit.GetParameter(1));
1806  oldpars.push_back(minuit.GetParameter(2));
1807  oldpars.push_back(minuit.GetParameter(3));
1808 
1809  double oldfit[4];
1810  oldfit[0] = minuit.GetParameter(1);
1811  oldfit[1] = minuit.GetParameter(0);
1812  oldfit[2] = minuit.GetParameter(3);
1813  oldfit[3] = minuit.GetParameter(2);
1814 
1815 #endif
1816 
1817  // Newer ROOT fitting interface
1818  ROOT::Math::MinimizerOptions::SetDefaultMinimizer("Minuit2","Migrad");
1819  ROOT::Math::MinimizerOptions::SetDefaultPrintLevel(-1);
1820  // set the function
1821  ROOT::Fit::Fitter fitter;
1822  ROOT::Math::Functor functor(*fcn,4);
1823  double values[4] = {fit[1], fit[0], fit[3], fit[2]};
1824  fitter.SetFCN(functor,values);
1825  // set initial values and step sizes
1826  ROOT::Fit::FitConfig& config = fitter.Config();
1827  config.ParSettings(0).Set("M", fit[1], 1.0);
1828  config.ParSettings(1).Set("XOff", fit[0], 100.0);
1829  config.ParSettings(2).Set("N", fit[3], 1.0);
1830  config.ParSettings(3).Set("YOff", fit[2], 100.0);
1831  // switch off debugging if requested
1832  int prevLevel = gErrorIgnoreLevel;
1833  if (fDebug < 2) // switch off printing of info messages in Minuit2
1834  gErrorIgnoreLevel = 1001;
1835  // fit the data with custom gErrorIgnoreLevel
1836  bool ok = fitter.FitFCN();
1837  // restore previous debug level
1838  gErrorIgnoreLevel = prevLevel;
1839  // check status
1840  if (!ok) QwVerbose << "Minuit: new fit failed!" << QwLog::endl;
1841  // get the results
1842  const ROOT::Fit::FitResult& result = fitter.Result();
1843 
1844  std::vector<double> newpars;
1845  newpars.push_back(result.Parameter(0));
1846  newpars.push_back(result.Parameter(1));
1847  newpars.push_back(result.Parameter(2));
1848  newpars.push_back(result.Parameter(3));
1849 
1850  double newfit[4]; double newerr[4];
1851  fit[0] = newfit[0] = result.Parameter(1); newerr[0] = result.ParError(1);
1852  fit[1] = newfit[1] = result.Parameter(0); newerr[1] = result.ParError(0);
1853  fit[2] = newfit[2] = result.Parameter(3); newerr[2] = result.ParError(3);
1854  fit[3] = newfit[3] = result.Parameter(2); newerr[3] = result.ParError(2);
1855 
1856 #if ROOT_VERSION_CODE < ROOT_VERSION(5,90,0)
1857  // Compare when both old and new fit are present
1858  if ((oldfit[0]-newfit[0])*(oldfit[0]-newfit[0])/newerr[0]/newerr[0]
1859  +(oldfit[1]-newfit[1])*(oldfit[1]-newfit[1])/newerr[1]/newerr[1]
1860  +(oldfit[2]-newfit[2])*(oldfit[2]-newfit[2])/newerr[2]/newerr[2]
1861  +(oldfit[3]-newfit[3])*(oldfit[3]-newfit[3])/newerr[3]/newerr[3]>0.01) {
1862  QwVerbose << "Old fit results: " << oldfit[0] << "," << oldfit[1] << "," << oldfit[2] << "," << oldfit[3] << " (" << fcn->operator()(oldpars) << ")" << QwLog::endl;
1863  QwVerbose << "New fit results: " << newfit[0] << "," << newfit[1] << "," << newfit[2] << "," << newfit[3] << " (" << fcn->operator()(newpars) << ")" << QwLog::endl;
1864  QwVerbose << "New fit errors: " << newerr[0] << "," << newerr[1] << "," << newerr[2] << "," << newerr[3] << QwLog::endl;
1865  }
1866 #endif
1867 
1868  for (int i = 0; i < num_hits; ++i)
1869  {
1870  // Normalization = 1/sigma^2
1871  double resolution = hits[i]->GetDetectorInfo()->GetSpatialResolution();
1872  double normalization = 1.0 / (resolution * resolution);
1873 
1874  // Get cos and sin of the wire angles of this plane
1875  double rcos = hits[i]->GetDetectorInfo()->GetElementAngleCos();
1876  double rsin = hits[i]->GetDetectorInfo()->GetElementAngleSin();
1877 
1878  // Absolute positions of the fitted position at this plane
1879  double x = fit[0] + fit[1] * hits[i]->GetDetectorInfo()->GetZPosition();
1880  double y = fit[2] + fit[3] * hits[i]->GetDetectorInfo()->GetZPosition();
1881 
1882  // Relative positions of the fitted position at this plane
1883  x -= hits[i]->GetDetectorInfo()->GetXPosition();
1884  y -= hits[i]->GetDetectorInfo()->GetYPosition();
1885 
1886  double dx = dx_[hits[i]->GetPlane() - 1];
1887 
1888  double wire_off = -0.5 * hits[i]->GetDetectorInfo()->GetElementSpacing()
1889  + hits[i]->GetDetectorInfo()->GetElementOffset();
1890  double hit_pos = hits[i]->GetDriftPosition() + wire_off - dx;
1891  double residual = y * rcos + x * rsin - hit_pos;
1892 
1893  // Update residuals
1894  hits[i]->SetPartialTrackPosition(dx - wire_off + y * rcos + x * rsin);
1895  hits[i]->CalculatePartialTrackResidual();
1896  QwDebug << "hit " << i << ": " << hits[i]->GetPartialTrackPosition() << QwLog::endl;
1897 
1898  signedresidual[hits[i]->GetPlane() - 1] = residual;
1899  residual = fabs(residual);
1900  if (residual > worst_case.second)
1901  {
1902  worst_case.first = i;
1903  worst_case.second = residual;
1904  }
1905 
1906  chi2 += normalization * residual * residual;
1907  }
1908 
1909  // Divide by degrees of freedom (number of hits minus two offsets, two slopes)
1910  // chi2 /= (num_hits - 4);
1911 
1912  //this is the minuit calculated chi2
1913  chi2 = fcn->operator()(newpars);
1914 
1915  // Return if we are done
1916  if (drop_worst_hit == false) {
1917 
1918 
1919  return 0;
1920  }
1921 
1922  double best_chi2 = chi2;
1923 
1924  /*
1925  * try to delete the worst point from the set of hit points, and repeat the
1926  * procedure one more time. Now it is temporarily turned off
1927  */
1928  double temp_residual[12];
1929 
1930  for (int i = 1; i < 12; ++i)
1931  temp_residual[i] = -10;
1932 
1933 
1934 
1935  int drop = worst_case.first;
1936  double fit_drop[4] = { 0.0 };
1937 
1938  // Initialize the matrices
1939  for (int i = 0; i < 4; ++i)
1940  {
1941  B[i] = 0.0;
1942  for (int j = 0; j < 4; ++j)
1943  A[i][j] = 0.0;
1944  }
1945 
1946  // Adjust the matrices A and B by ignoring the worst hit
1947  for (int i = 0; i < num_hits; ++i)
1948  {
1949  // Skip the dropped hit
1950  if (i == drop) continue;
1951 
1952  // Normalization = 1/sigma^2
1953  double resolution = hits[i]->GetDetectorInfo()->GetSpatialResolution();
1954  double normalization = 1.0 / (resolution * resolution);
1955 
1956  // Get cos and sin of the wire angles of this plane
1957  double rcos = hits[i]->GetDetectorInfo()->GetElementAngleCos();
1958  double rsin = hits[i]->GetDetectorInfo()->GetElementAngleSin();
1959 
1960  // Determine the offset of the center of this plane
1961  double center_x = hits[i]->GetDetectorInfo()->GetXPosition();
1962  double center_y = hits[i]->GetDetectorInfo()->GetYPosition();
1963  double center_offset = rcos * center_y + rsin * center_x;
1964 
1965  // TODO
1966  double dx = dx_[hits[i]->GetPlane() - 1];
1967 
1968  double wire_off = -0.5 * hits[i]->GetDetectorInfo()->GetElementSpacing()
1969  + hits[i]->GetDetectorInfo()->GetElementOffset();
1970  double hit_pos = hits[i]->GetDriftPosition() + wire_off - dx;
1971 
1972  double r[4];
1973  r[0] = rsin;
1974  r[1] = rsin * (hits[i]->GetDetectorInfo()->GetZPosition());
1975  r[2] = rcos;
1976  r[3] = rcos * (hits[i]->GetDetectorInfo()->GetZPosition());
1977  for (int k = 0; k < 4; k++)
1978  {
1979  B[k] += normalization * r[k] * (hit_pos + center_offset);
1980  for (int j = 0; j < 4; j++)
1981  A[k][j] += normalization * r[k] * r[j];
1982  }
1983  } // end of the for loop for num_hits
1984 
1985  M_Invert(Ap, cov, 4);
1986 
1987  // Check that inversion was successful
1988  if (!cov)
1989  {
1990  cerr << "Inversion failed" << endl;
1991  return -1;
1992  }
1993 
1994  // Calculate the fit
1995  M_A_times_b(fit_drop, cov, 4, 4, B); // fit = matrix cov * vector B
1996 
1997  // Calculate chi2^2, rewrite
1998  double chi2_test = 0.0;
1999  for (int i = 0; i < num_hits; i++)
2000  {
2001  // Skip the dropped hit
2002  if (i == drop) continue;
2003 
2004 
2005  // Normalization = 1/sigma^2
2006  double resolution = hits[i]->GetDetectorInfo()->GetSpatialResolution();
2007  double normalization = 1.0 / (resolution * resolution);
2008 
2009  // Get cos and sin of the wire angles of this plane
2010  double rcos = hits[i]->GetDetectorInfo()->GetElementAngleCos();
2011  double rsin = hits[i]->GetDetectorInfo()->GetElementAngleSin();
2012 
2013  // Absolute positions of the fitted position at this plane
2014  double x = fit_drop[0] + fit_drop[1] * hits[i]->GetDetectorInfo()->GetZPosition();
2015  double y = fit_drop[2] + fit_drop[3] * hits[i]->GetDetectorInfo()->GetZPosition();
2016 
2017  // Relative positions of the fitted position at this plane
2018  x -= hits[i]->GetDetectorInfo()->GetXPosition();
2019  y -= hits[i]->GetDetectorInfo()->GetYPosition();
2020 
2021  double dx = dx_[hits[i]->GetPlane() - 1];
2022 
2023  double wire_off = -0.5 * hits[i]->GetDetectorInfo()->GetElementSpacing()
2024  + hits[i]->GetDetectorInfo()->GetElementOffset();
2025  double hit_pos = hits[i]->GetDriftPosition() + wire_off - dx;
2026  double residual = y * rcos + x * rsin - hit_pos;
2027 
2028  // Update residuals
2029  hits[i]->SetPartialTrackPosition(dx - wire_off + y * rcos + x * rsin);
2030  hits[i]->CalculatePartialTrackResidual();
2031  QwDebug << "hit " << i << ": " << hits[i]->GetPartialTrackPosition() << QwLog::endl;
2032 
2033  temp_residual[hits[i]->GetPlane() - 1] = residual;
2034  chi2_test += normalization * residual * residual;
2035 
2036  }
2037 
2038  // Divide by degrees of freedom (number of hits minus one dropped hit, two offsets, two slopes)
2039  chi2_test /= (num_hits - 5);
2040 
2041 
2042  // If new chi^2 is less than 80% of the original chi^2, use the improved version
2043  if (chi2_test < 0.8 * best_chi2)
2044  {
2045  best_chi2 = chi2_test;
2046  for (int k = 0; k < 4; ++k)
2047  fit[k] = fit_drop[k];
2048  for (int k = 0; k < 12; ++k)
2049  signedresidual[k] = temp_residual[k];
2050  }
2051 
2052  chi2 = best_chi2;
2053 
2054 
2055  return 0;
2056 }
2057 
2058 
2059 // NOTE:this version is using information directly from the treeline in plane0 to do the reconstruction
2061  const QwTreeLine* wu,
2062  const QwTreeLine* wv)
2063 {
2064  // Initialize variables
2065  double fit[4];
2066  double cov[4][4];
2067  for (size_t i = 0; i < 4; i++) {
2068  fit[i] = 0;
2069  for (size_t j = 0; j < 4; j++)
2070  cov[i][j] = 0.0;
2071  }
2072 
2073  // NOTE: first get angle information to transfer xy to uv
2074  double angle = wu->GetHit(0)->GetDetectorInfo()->GetElementAngle();
2075  Uv2xy uv2xy(angle, 2*Qw::pi - angle);
2076  //
2077  double rCos[kNumDirections],rSin[kNumDirections];
2078  rCos[kDirectionU] = uv2xy.fXY[0][0];
2079  rCos[kDirectionV] = uv2xy.fXY[1][0];
2080  rSin[kDirectionU] = uv2xy.fXY[0][1];
2081  rSin[kDirectionV] = uv2xy.fXY[1][1];
2082 
2083  // NOTE: the parameter contains the uoffset, uslope,voffset,vslope from treeline 0
2084  // TASK: transfer partial track in u/v to xy(local coordination)
2085  double perp;
2086  // NOTE: contains some magic number from geometry file
2087  // Hard coded values to be updated
2088  double uvshift = 2.54;
2089 
2090  if (wu->GetHit(0)->GetDetectorInfo()->GetPackage() == kPackage1)
2091  perp = 39.3679;
2092  else
2093  perp = 39.2835;
2094 
2095  double ufront = -wu->fOffset / wu->fSlope;
2096  double uback = ufront + perp / wu->fSlope;
2097 
2098  double vfront = -wv->fOffset / wv->fSlope;
2099  double vback = vfront + perp / wv->fSlope;
2100 
2101  double Pufront[3],Puback[3],Pvfront[3],Pvback[3];
2102  // NOTE: plane needs four pars to describe ax+by+cz+d=0, here we assume b=1;
2103  double uplane[4],vplane[4];
2104  Pufront[0] = ufront*rCos[kDirectionU];
2105  Pufront[1] = ufront*rSin[kDirectionU];
2106  Pufront[2] = 0;
2107  Puback[0] = uback*rCos[kDirectionU];
2108  Puback[1] = uback*rSin[kDirectionU];
2109  Puback[2] = perp+Pufront[2];
2110  uplane[0] = -fabs(rCos[kDirectionU]/rSin[kDirectionU]);
2111  uplane[1] = 1;
2112  uplane[3] = -(Pufront[1]+uplane[0]*Pufront[0]);
2113  uplane[2] = -(uplane[0]*Puback[0]+uplane[1]*Puback[1]+uplane[3])/Puback[2];
2114 
2115  Pvfront[0] = vfront*rCos[kDirectionV];
2116  Pvfront[1] = vfront*rSin[kDirectionV];
2117  Pvfront[2] = -uvshift;
2118  Pvback[0] = vback*rCos[kDirectionV];
2119  Pvback[1] = vback*rSin[kDirectionV];
2120  Pvback[2] = perp+Pvfront[2];
2121  vplane[0] = fabs(rCos[kDirectionV]/rSin[kDirectionV]);
2122  vplane[1] = 1;
2123  vplane[2] = (-(vplane[0]*Pvfront[0]+vplane[1]*Pvfront[1])+(vplane[0]*Pvback[0]+vplane[1]*Pvback[1]))/(Pvfront[2]-Pvback[2]);
2124  vplane[3] = -(vplane[0]*Pvfront[0]+vplane[1]*Pvfront[1])-vplane[2]*Pvfront[2];
2125 
2126 
2127  // TASK 2:hook two planes together to get partial track in local xy;
2128  double P[3],P_dir[3];
2129 
2130  P_dir[0]=uplane[1]*vplane[2]-uplane[2]*vplane[1];
2131  P_dir[1]=uplane[2]*vplane[0]-uplane[0]*vplane[2];
2132  P_dir[2]=uplane[0]*vplane[1]-uplane[1]*vplane[0];
2133 
2134 
2135  P[0]=-(uplane[3]-vplane[3])/(uplane[0]-vplane[0]);
2136  P[1]=-(uplane[0]*P[0]+uplane[3]);
2137  P[2]=0;
2138 
2139 
2140  fit[0]=P[0];
2141  fit[1]=P_dir[0]/P_dir[2];
2142  fit[2]=P[1];
2143  fit[3]=P_dir[1]/P_dir[2];
2144 
2145  // TASK 3: rotate xy local to the global coordination(partially because of y axis)
2146  double P1[3],P2[3],Pp1[3],Pp2[3];
2147  double ztrans,ytrans,xtrans,costheta,sintheta,cosphi,sinphi;
2148  //get some detector information
2149  // NOTE: since the first plane is in v direction and hits[0] is in u, so here 1 should be changed to 2
2150 
2151  //if ( wu->GetHit(0)->GetDetectorInfo()->GetPlane() == 2 )
2152 
2153  QwVerbose << "TODO (wdc) needs checking" << QwLog::endl;
2154  costheta = wu->GetHit(0)->GetDetectorInfo()->GetDetectorPitchCos();
2155  sintheta = wu->GetHit(0)->GetDetectorInfo()->GetDetectorPitchSin();
2156  cosphi = wu->GetHit(0)->GetDetectorInfo()->GetDetectorRollCos();
2157  sinphi = wu->GetHit(0)->GetDetectorInfo()->GetDetectorRollSin();
2158 
2159  /// xtrans,ytrans,ztrans are first plane's information
2160  // Due to different handedness, package1's first plane is u,
2161  // package2's first plane is v
2162  if(wu->GetHit(0)->GetDetectorInfo()->GetPackage()==1)
2163  {
2164  if( wu->GetHit(0)->GetDetectorInfo()->GetDirection()== kDirectionU )
2165  {
2166  xtrans = wu->GetHit(0)->GetDetectorInfo()->GetXPosition();
2167  ytrans = wu->GetHit(0)->GetDetectorInfo()->GetYPosition();
2168  ztrans = wu->GetHit(0)->GetDetectorInfo()->GetZPosition();
2169  }
2170  else
2171  {
2172  QwWarning << "Error : first hit is not in 1st plane" << QwLog::endl;
2173  return 0;
2174  }
2175  }
2176  else
2177  {
2178  if( wv->GetHit(0)->GetDetectorInfo()->GetDirection()== kDirectionV )
2179  {
2180  xtrans = wv->GetHit(0)->GetDetectorInfo()->GetXPosition();
2181  ytrans = wv->GetHit(0)->GetDetectorInfo()->GetYPosition();
2182  ztrans = wv->GetHit(0)->GetDetectorInfo()->GetZPosition();
2183  }
2184  else
2185  {
2186  QwWarning << "Error : first hit is not in 1st plane" << QwLog::endl;
2187  return 0;
2188  }
2189  }
2190 
2191  //std::cout<<"(xtrans,ytrans,ztrans) = ("<<xtrans<<", "<<ytrans<<", "<<ztrans<<")"<<std::endl;
2192 
2193 
2194  P1[2] = 69.9342699;
2195  P1[0] = fit[1] * P1[2] + fit[0];
2196  P1[1] = fit[3] * P1[2] + fit[2];
2197  P2[2] = 92.33705405;
2198  P2[0] = fit[1] * P2[2] + fit[0];
2199  P2[1] = fit[3] * P2[2] + fit[2];
2200 
2201  // rotate the points into the lab orientation
2202  // translate the points into the lab frame
2203 
2204  Pp1[0] = (ytrans + P1[0] * costheta + P1[2] * sintheta) * cosphi + (xtrans + P1[1]) * sinphi;
2205  Pp1[1] = -1*(ytrans + P1[0] * costheta + P1[2] * sintheta) * sinphi + (xtrans + P1[1]) * cosphi;
2206  Pp1[2] = ztrans - P1[0] * sintheta + P1[2] * costheta;
2207 
2208  Pp2[0] = (ytrans + P2[0] * costheta + P2[2] * sintheta) * cosphi + (xtrans + P2[1]) * sinphi;
2209  Pp2[1] = -1*(ytrans + P2[0] * costheta + P2[2] * sintheta) * sinphi + (xtrans + P2[1]) * cosphi;
2210  Pp2[2] = ztrans - P2[0] * sintheta + P2[2] * costheta;
2211 
2212  // Calculate the new line
2213  fit[1] = ( Pp2[0] - Pp1[0] ) / ( Pp2[2] - Pp1[2] );
2214  fit[3] = ( Pp2[1] - Pp1[1] ) / ( Pp2[2] - Pp1[2] );
2215  fit[0] = Pp2[0] - fit[1] * Pp2[2];
2216  fit[2] = Pp2[1] - fit[3] * Pp2[2];
2217 
2218 
2219  // Create partial track
2220  QwPartialTrack* pt = new QwPartialTrack();
2221 
2222  // NOTE Why here x and y are swapped because of different coordinate systems
2223  // first assume it's in the octant 3, then call rotate method in pt class to rotate it to the right position
2224  pt->fOffsetX = -fit[2]; /// \todo why the minus sign here?
2225  pt->fOffsetY = fit[0];
2226  pt->fSlopeX = -fit[3]; /// \todo why the minus sign here?
2227  pt->fSlopeY = fit[1];
2228  // Debug output
2229  QwDebug << "Reconstructed partial track in x,y (local)" << QwLog::endl;
2230  QwDebug << "x = " << pt->fOffsetX << " + z * " << pt->fSlopeX << QwLog::endl;
2231  QwDebug << "y = " << pt->fOffsetY << " + z * " << pt->fSlopeY << QwLog::endl;
2232 
2233  // Add number of hits
2234  pt->fNumHits = wu->fNumHits + wv->fNumHits;
2235 
2236  // Store copy of treeline
2237  pt->AddTreeLine(wu);
2238  pt->AddTreeLine(wv);
2239 
2240  pt->fIsVoid = false;
2241 
2242  // chi
2243  pt->fChi = sqrt(wu->fChi*wu->fChi + wv->fChi*wv->fChi); /// \todo chi2(pt) =?= sum chi2(tl) for R3
2244  // Covariance matrix
2245  for (int i = 0; i < 4; i++)
2246  for (int j = 0; j < 4; j++)
2247  pt->fCov[i][j] = cov[i][j];
2248 
2249  // Return partial track
2250  return pt;
2251 }
2252 
2253 
2254 /*!--------------------------------------------------------------------------*\
2255 
2256  \brief The
2257 
2258  This function fits a set of hits in the HDC to a 3-D track. This
2259  task is complicated by the unorthogonality of the u,v, and x wire
2260  planes. To obtain the track, the metric matrix (defined below) is
2261  calculated using the projections of each hit into the lab
2262  coordinate system. The matrix is inverted in order to solve the
2263  system of four equations for the four unknown track parameters
2264  (bx,mx,by,my). Once the fit is calculated, the chisquare value
2265  is determined so that this track may be compared to other track
2266  candidates in order to select the best fit.
2267 
2268  metric matrix : The metric matrix is defined by the chi-squared
2269  equation for unorthogonal coordinate systems. In order to
2270  solve for the four track parameters, chi-square is
2271  differentiated with respect to the parameters, and set to
2272  zero. The metric matrix is then derived from the four
2273  equations using the standard linear algebra technique for
2274  solving systems of equations.
2275 
2276  *//*-------------------------------------------------------------------------*/
2277 
2279  QwTreeLine *wu,
2280  QwTreeLine *wv,
2281  QwTreeLine *wx,
2282  int tlayer,
2283  bool drop_worst_hit)
2284 {
2285  QwHit *hits[3 * DLAYERS];
2286  for (int i = 0; i < 3 * DLAYERS; i++)
2287  hits[i] = 0;
2288 
2289  QwHit **hitarray = 0;
2290  QwHit *h = 0;
2291 
2292  // Initialize fit results and covariance matrix
2293  double fit[4];
2294  double cov[4][4];
2295  double *covp = &cov[0][0];
2296  for (int i = 0; i < 4; ++i)
2297  {
2298  fit[i] = 0;
2299  for (int j = 0; j < 4; ++j)
2300  cov[i][j] = 0;
2301  }
2302 
2303  // Initialize residuals for each plane
2304  double residual[12];
2305  for (int i = 0; i < 12; ++i)
2306  residual[i] = -10;
2307 
2308 
2309  // Put all the hits into one array
2310  int hitc = 0;
2311  for (EQwDirectionID dir = kDirectionX; dir <= kDirectionV; dir++)
2312  {
2313  switch (dir)
2314  {
2315  case kDirectionU:
2316  hitarray = wu->fHits;
2317  break;
2318  case kDirectionV:
2319  hitarray = wv->fHits;
2320  break;
2321  case kDirectionX:
2322  hitarray = wx->fHits;
2323  break;
2324  default:
2325  hitarray = 0;
2326  break;
2327  }
2328  if (!hitarray)
2329  continue;
2330 
2331  for (int num = MAXHITPERLINE * DLAYERS; num-- && *hitarray; ++hitarray)
2332  {
2333  h = *hitarray;
2334  if (h->IsUsed() != 0 && hitc < DLAYERS * 3)
2335  {
2336  //if(h->GetDirection()!=kDirectionX)
2337  hits[hitc++] = h;
2338  //else if(h->GetPlane()==1 || h->GetPlane()==7 || h->GetPlane()==4 || h->GetPlane()==10)
2339  // hits[hitc++] = h;
2340  }
2341  }
2342  }
2343 
2344  // Perform the fit
2345  double chi = 0.0;
2346  if (r2_PartialTrackFit(hitc, hits, fit, covp, chi, residual, drop_worst_hit) == -1)
2347  {
2348  QwWarning << "QwPartialTrack Fit Failed" << QwLog::endl;
2349  return 0;
2350  }
2351 
2352  // Create new partial track
2353  QwPartialTrack* pt = new QwPartialTrack();
2354 
2355  // Store the track offset and slope in the correct coordinate frame
2356  pt->fOffsetX = -fit[0];
2357  pt->fOffsetY = fit[2];
2358  pt->fSlopeX = -fit[1];
2359  pt->fSlopeY = fit[3];
2360 
2361  pt->fIsVoid = false;
2362 
2363  pt->fChi = sqrt(chi);
2364 
2365  // TODO FIXME
2367 
2368  // Store covariance matrix
2369  for (int i = 0; i < 4; i++)
2370  for (int j = 0; j < 4; j++)
2371  pt->fCov[i][j] = cov[i][j];
2372 
2373  // Store residuals for each plane
2374  for (int i = 0; i < 12; ++i)
2375  pt->fSignedResidual[i] = residual[i];
2376 
2377  pt->fNumMiss = wu->fNumMiss + wv->fNumMiss + wx->fNumMiss;
2378  pt->fNumHits = wu->fNumHits + wv->fNumHits + wx->fNumHits;
2379 
2380  // Store tree lines info
2381  pt->AddTreeLine(wx);
2382  pt->AddTreeLine(wu);
2383  pt->AddTreeLine(wv);
2384 
2388 
2389  // Return the partial track
2390  return pt;
2391 }
2392 
2393 
2394 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
2395 
2396 /* ------------------------------
2397  Combines u v and x to tracks
2398  in space.
2399  ------------------------------ */
2400 /*INPUT:
2401  treelines : u and v direction
2402  bins : number of bins in one layer
2403 
2404  OUTPUT:
2405  (old) uvl gets new treelines for the front x direction
2406  uvl : is used in TcTreeLineCombine
2407  QwPartialTrack ret: a 3-D track
2408 
2409 
2410  */
2411 std::vector<QwPartialTrack*> QwTrackingTreeCombine::TlTreeCombine (
2412  const std::vector<QwTreeLine*>& treelines_x,
2413  const std::vector<QwTreeLine*>& treelines_u,
2414  const std::vector<QwTreeLine*>& treelines_v,
2415  EQwDetectorPackage package,
2416  EQwRegionID region,
2417  int tlayer,
2418  int dlayer)
2419 {
2420  QwDebug << "[QwTrackingTreeCombine::TlTreeCombine]" << QwLog::endl;
2421 
2422  // List of partial tracks to return
2423  std::vector<QwPartialTrack*> parttracklist;
2424 
2425  //################
2426  // DECLARATIONS #
2427  //################
2428  int nPartialTracks = 0;
2429 
2430  const int MAXIMUM_PARTIAL_TRACKS = 50;
2431 
2432  //#################################
2433  // Get the x, u, and v tree lines #
2434  //#################################
2435 
2436  switch (region) {
2437 
2438  //################
2439  // REGION 3 VDC #
2440  //################
2441  case kRegionID3:
2442  {
2443 
2444  //#########################
2445  // Get the u and v tracks #
2446  //#########################
2447 
2448  // For 2 plane 0 counters only counters
2449  int nump0 = 0;
2450  int count = 0;
2451  // Count number of U treelines
2452  for (size_t u = 0; u < treelines_u.size(); u++) {
2453  // Get treeline
2454  QwTreeLine* wu = treelines_u[u];
2455 
2456  // Debug
2457  if (fDebug) {
2458  QwOut << "wu: " << *wu << QwLog::endl;
2459  for (int hit = 0; hit < wu->GetNumberOfHits(); hit++)
2460  QwOut << *(wu->GetHit(hit)) << QwLog::endl;
2461  }
2462 
2463  // Skip all treelines in a single plane (not matched between chambers)
2464  if (wu->GetPlane() > 0) continue;
2465 
2466  // Skip this treeline if it was no good
2467  if (wu->IsVoid()) continue;
2468 
2469  count++;
2470  }
2471  if (count < 2) {
2472  count = 0;
2473  // Count number of V treelines
2474  for (size_t v = 0; v < treelines_v.size(); v++) {
2475  // Get treeline
2476  QwTreeLine* wv = treelines_v[v];
2477 
2478  // Debug
2479  if (fDebug) {
2480  QwOut << "wv: " << *wv << QwLog::endl;
2481  for (int hit = 0; hit < wv->GetNumberOfHits(); hit++)
2482  QwOut << *(wv->GetHit(hit)) << QwLog::endl;
2483  }
2484 
2485  // Skip all treelines in a single plane (not matched between chambers)
2486  if (wv->GetPlane() > 0) continue;
2487 
2488  // Skip this treeline if it was no good
2489  if (wv->IsVoid()) continue;
2490 
2491  count++;
2492  }
2493  }
2494  if (count < 2) nump0 = 1;
2495 
2496 
2497  // Get the U treeline
2498  for (size_t u = 0; u < treelines_u.size(); u++) {
2499  // Get treeline
2500  QwTreeLine* wu = treelines_u[u];
2501 
2502  // Skip all treelines in a single plane (not matched between chambers)
2503  if (wu->GetPlane() > 0) continue;
2504 
2505  // Skip this treeline if it was no good
2506  if (wu->IsVoid()) continue;
2507 
2508  // Get the V treeline
2509  for (size_t v = 0; v < treelines_v.size(); v++) {
2510  // Get treeline
2511  QwTreeLine* wv = treelines_v[v];
2512 
2513  // Skip all treelines in a single plane (not matched between chambers)
2514  if (wv->GetPlane() > 0) continue;
2515 
2516  // Skip this treeline if it was no good
2517  if (wv->IsVoid()) continue;
2518 
2519  // Combine the U and V treeline into a partial track
2520  QwPartialTrack *pt = r3_PartialTrackFit(wu, wv);
2521 
2522  // If a partial track was found
2523  if (pt) {
2524  // Set geometry identification
2525  pt->SetRegion(region);
2526  pt->SetPackage(package);
2527  pt->SetOctant(wu->GetOctant());
2528  pt->RotateCoordinates();
2529  if(gQwOptions.GetValue<bool>("QwTracking.R3.RotatorTilt"))
2530  pt->RotateRotator(wu->GetHit(0)->GetDetectorInfo());
2531 
2532  // Set 2 plane 0 treelines only
2533  pt->SetAlone(nump0);
2534 
2535  // Add partial track to list to return
2536  parttracklist.push_back(pt);
2537  }
2538 
2539  } // end of loop over V treelines
2540  } // end of loop over U treelines
2541 
2542  break;
2543  }
2544 
2545  //################
2546  // REGION 2 HDC #
2547  //################
2548  case kRegionID2:
2549  {
2550 
2551  //############################
2552  // Get the u, v and x tracks #
2553  //############################
2554 
2555  // Find the partial track with the lowest chi^2
2556  double best_chi = 10000;
2557  QwPartialTrack* best_pt = 0;
2558  QwTreeLine* best_tl[3] = {0};
2559 
2560  // while (nPartialTracks < MAXIMUM_PARTIAL_TRACKS)
2561 
2562  // Get the U treeline
2563  for (size_t u = 0; u < treelines_u.size(); u++) {
2564  // Get treeline
2565  QwTreeLine* wu = treelines_u[u];
2566 
2567  // Debug
2568  if (fDebug) {
2569  QwOut << "wu: " << *wu << QwLog::endl;
2570  for (int hit = 0; hit < wu->GetNumberOfHits(); hit++)
2571  QwOut << *(wu->GetHit(hit)) << QwLog::endl;
2572  }
2573 
2574  // Skip this treeline if it was no good
2575  if (wu->IsVoid()) continue;
2576 
2577  // Get the V treeline
2578  for (size_t v = 0; v < treelines_v.size(); v++) {
2579  // Get treeline
2580  QwTreeLine* wv = treelines_v[v];
2581 
2582  // Debug
2583  if (fDebug) {
2584  QwOut << "wv: " << *wv << QwLog::endl;
2585  for (int hit = 0; hit < wv->GetNumberOfHits(); hit++)
2586  QwOut << *(wv->GetHit(hit)) << QwLog::endl;
2587  }
2588 
2589  // Skip this treeline if it was no good
2590  if (wv->IsVoid()) continue;
2591 
2592  // Get the V treeline
2593  for (size_t x = 0; x < treelines_x.size(); x++) {
2594  // Get treeline
2595  QwTreeLine* wx = treelines_x[x];
2596 
2597  // Debug
2598  if (fDebug) {
2599  QwOut << "wx: " << *wx << QwLog::endl;
2600  for (int hit = 0; hit < wx->GetNumberOfHits(); hit++)
2601  QwOut << *(wx->GetHit(hit)) << QwLog::endl;
2602  }
2603 
2604  // Skip this treeline if it was no good
2605  if (wx->IsVoid()) continue;
2606 
2607  // Combine the U, V and X treeline into a partial track
2608  QwPartialTrack *pt = TcTreeLineCombine(wu, wv, wx, tlayer, fDropWorstHit);
2609 
2610  // If a partial track was found
2611  if (pt) {
2612  // Find partial track with best chi
2613  if (pt->fChi < best_chi) {
2614  // Update best partial track
2615  if (best_pt) {
2616  delete best_pt;
2617  best_pt = 0;
2618  }
2619  best_pt = pt;
2620  // Update best chi
2621  best_chi = best_pt->fChi;
2622 
2623  // Set geometry identification
2624  best_pt->SetRegion(region);
2625  best_pt->SetPackage(package);
2626  best_pt->SetOctant(wv->GetOctant());
2627  best_pt->RotateCoordinates();
2628 
2629  best_tl[0] = wx;
2630  best_tl[1] = wu;
2631  best_tl[2] = wv;
2632 
2633  } else {
2634  // Delete the partial track
2635  delete pt;
2636  }
2637  }
2638 
2639  } // end of loop over X treelines
2640 
2641  } // end of loop over V treelines
2642 
2643  } // end of loop over U treelines
2644 
2645  // If there was a best partial track
2646  if (best_pt) {
2647  ++nPartialTracks;
2648 
2649  best_tl[0]->SetUsed();
2650  best_tl[1]->SetUsed();
2651  best_tl[2]->SetUsed();
2652 
2653  // Add partial track to list to return
2654  parttracklist.push_back(best_pt);
2655  }
2656 
2657 
2658  if (nPartialTracks >= MAXIMUM_PARTIAL_TRACKS)
2659  QwWarning << "Wow, that's a lot of partial tracks!" << QwLog::endl;
2660 
2661 
2662  break;
2663  }
2664 
2665 
2666  //#################
2667  // OTHER REGIONS #
2668  //#################
2669  default:
2670  {
2671  QwError << "[QwTrackingTreeCombine::TlTreeCombine] Error: "
2672  << "Region " << region << " not supported!" << QwLog::endl;
2673  break;
2674  }
2675 
2676  } // end of switch on region
2677 
2678 
2679  // Calculate the average residual
2680  for (size_t pt = 0; pt < parttracklist.size(); pt++) {
2681  QwPartialTrack* parttrack = parttracklist[pt];
2682  if (parttrack->IsValid())
2683  parttrack->CalculateAverageResidual();
2684  }
2685 
2686 
2687  return parttracklist;
2688 }
2689 
2690 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo....
double fChi
chi squared(?)
Definition: QwTreeLine.h:215
static const double pi
Angles: base unit is radian.
Definition: QwUnits.h:102
static const double G
Definition: QwUnits.h:112
#define QwOut
Predefined log drain for explicit output.
Definition: QwLog.h:35
void CalculateTreeLineResidual()
Definition: QwHit.h:156
double GetDetectorPitchSin() const
int fMaxMissedWires
Maximum number of missed wires in region 3.
bool TlCheckForX(double x1, double x2, double dx1, double dx2, double Dx, double z1, double dz, QwTreeLine *treefill, QwHitContainer *hitlist, int dlayer, int tlayer, int iteration, int stay_tuned, double width)
double fOffset
track offset
Definition: QwTreeLine.h:213
int TlMatchHits(double x1, double x2, double z1, double z2, QwTreeLine *treeline, QwHitContainer *hitlist, int tlayers)
const std::vector< QwHit * > & GetListOfHits() const
Get the list of hits.
Definition: QwTreeLine.h:115
Double_t fOffsetX
x coordinate (at MAGNET_CENTER)
double * M_Invert(double *Ap, double *Bp, const int n)
Matrix inversion of Ap will be stored in Bp.
Definition: matrix.cc:240
const QwGeometry in(const EQwRegionID &r) const
Get detectors in given region.
Definition: QwGeometry.h:92
double GetSpatialResolution() const
int fR3Offset
offset of demultiplexed group of 8
Definition: QwTreeLine.h:228
int GetElement() const
Get the element number.
EQwDetectorPackage GetPackage() const
Int_t GetNumberOfHits() const
Get the number of hits.
Definition: QwTreeLine.h:109
QwPartialTrack * r3_PartialTrackFit(const QwTreeLine *wu, const QwTreeLine *wv)
const Bool_t & IsUsed() const
Definition: QwHit.h:101
void SetRegion(EQwRegionID region)
Set the region.
Double_t fSlopeY
y slope
double GetResolutionLast(const double binwidth)
Returns resolution at the last detector plane.
Definition: QwTreeLine.h:155
void SetTreeLinePosition(const Double_t position)
Definition: QwHit.h:130
double GetAverageResidual() const
Get the average residuals.
Definition: QwTreeLine.h:163
int GetOctant() const
Get the octant number.
#define QwVerbose
Predefined log drain for verbose messages.
Definition: QwLog.h:55
void SetSlope(const double slope)
Set the slope.
Definition: QwTreeLine.h:177
EQwDirectionID GetDirection() const
Double_t fChi
combined chi square
double fSlope
track slope
Definition: QwTreeLine.h:214
#define DLAYERS
Definition: globals.h:5
QwOptions gQwOptions
Definition: QwOptions.cc:27
void SetPackage(EQwDetectorPackage package)
Set the package.
void SetUsed(const Bool_t isused=true)
Definition: QwHit.h:138
double GetPositionLast(const double binwidth)
Returns position at the last detector plane.
Definition: QwTreeLine.h:145
bool InAcceptance(EQwDetectorPackage package, EQwRegionID region, double cx, double mx, double cy, double my)
void SetVoid(const bool isvoid=true)
Definition: QwTreeLine.h:88
void TlTreeLineSort(QwTreeLine *tl, QwHitContainer *hl, EQwDetectorPackage package, EQwRegionID region, EQwDirectionID dir, unsigned long bins, int tlayer, int dlayer, double width)
EQwDetectorPackage
Definition: QwTypes.h:70
Definition of the partial track class.
int fR3LastWire
first and last wire in group of 8
Definition: QwTreeLine.h:229
int fMaxMissedPlanes
Maximum number of missed planes in region 2.
double GetDetectorPitchCos() const
void AddTreeLine(const QwTreeLine *treeline)
Add an existing tree line as a copy.
#define MAGNET_CENTER
Definition of the track class.
EQwRegionID GetRegion() const
Get the region.
std::vector< QwPartialTrack * > TlTreeCombine(const std::vector< QwTreeLine * > &treelines_x, const std::vector< QwTreeLine * > &treelines_u, const std::vector< QwTreeLine * > &treelines_v, EQwDetectorPackage package, EQwRegionID region, int tlayer, int dlayer)
Double_t fDriftPosition
Position of the decoded hit in the drift cell.
Definition: QwHit.h:186
void SetChi(const double chi)
Set the chi^2.
Definition: QwTreeLine.h:181
#define MAXHITPERLINE
Definition: globals.h:12
T GetValue(const std::string &key)
Get a templated value.
Definition: QwOptions.h:240
double GetPlaneOffset() const
int GetPlane() const
Get the plane number.
int r2_PartialTrackFit(const int num_hits, QwHit **hits, double *fit, double *cov, double &chi2, double *signedresidual, bool drop_worst_hit)
EQwRegionID
Definition: QwTypes.h:16
#define QwDebug
Predefined log drain for debugging output.
Definition: QwLog.h:60
void SetValid(const bool isvoid=false)
Definition: QwTreeLine.h:91
QwHit * GetHit(int i=0)
Get a specific hit.
Definition: QwTreeLine.cc:234
bool fDropWorstHit
Drop the hit with largest residual and attempt partial track fit again in region 2.
void RotateCoordinates()
Rotate coordinates to right octant.
A logfile class, based on an identical class in the Hermes analyzer.
double Up() const
const Double_t & GetTreeLineResidual() const
Definition: QwHit.h:97
void Print(const Option_t *options=0) const
Definition: QwTreeLine.cc:317
void SetOctant(int octant)
Set the octant number.
std::vector< QwHit * > hits
const Double_t & GetDriftDistance() const
Definition: QwHit.h:92
double GetPositionFirst(const double binwidth)
Returns position at the first detector plane.
Definition: QwTreeLine.h:140
double CalculateAverageResidual()
void SetAlone(const int alone)
int SelectLeftRightHit(double *xresult, double dist_cut, QwHitContainer *hitlist, QwHit **ha, double Dx=0)
Select the left or right hit assignment for HDC hits.
bool InAcceptance(const double x, const double y) const
Double_t fCov[4][4]
covariance matrix
int fNumHits
number of hits on this treeline
Definition: QwTreeLine.h:221
void SetOffset(const double offset)
Set the offset.
Definition: QwTreeLine.h:173
const Double_t & GetDriftPosition() const
Definition: QwHit.h:93
void SetAverageResidual(const double residual)
double * M_A_times_b(double *y, const double *A, const int n, const int m, const double *b)
Calculates y[n] = A[n,m] * b[m], with dimensions indicated.
Definition: matrix.cc:443
Double_t fSlopeX
x slope
A helper object for transformation between [u,v] and [x,y] frames.
Definition of the one-dimensional track stubs.
Bool_t fIsVoid
marked as being void
Converts between (u,v) and (x,y) coordinates.
Definition: uv2xy.h:52
void SetDetectorInfo(const QwDetectorInfo *detectorinfo)
Set the detector info pointer.
Double_t TResidual[kNumDirections]
double GetDetectorRollCos() const
bool IsVoid() const
Is this tree line void?
Definition: QwTreeLine.h:87
std::vector< int > fMatchingPattern
Definition: QwTreeLine.h:212
double GetResolutionFirst(const double binwidth)
Returns resolution at the first detector plane.
Definition: QwTreeLine.h:151
double GetYPosition() const
int GetCrosstalkElement(int element) const
One-dimensional (u, v, or x) track stubs and associated hits.
Definition: QwTreeLine.h:51
double GetElementAngleSin() const
int fNumMiss
number of planes without hits
Definition: QwTreeLine.h:222
std::pair< double, double > CalculateDistance(int row, double width, unsigned int bins, double error)
calculate the upper and lower bound of the drift distance give the row number
Definition: QwTreeLine.cc:374
static std::ostream & endl(std::ostream &)
End of the line.
Definition: QwLog.cc:299
void SetCov(const double *cov)
Set the covariance.
Definition: QwTreeLine.h:185
void DeleteHit(const size_t i)
Delete a single hit.
Definition: QwTreeLine.cc:209
void r2_TreelineFit(double &slope, double &offset, double cov[3], double &chi, QwHit **hits, int n)
const QwDetectorInfo * GetDetectorInfo() const
Get the detector info pointer.
EQwDirectionID
Definition: QwTypes.h:41
void RotateRotator(const QwDetectorInfo *geometry)
Collection of QwDetectorInfo pointers that specifies an experimental geometry.
Definition: QwGeometry.h:27
void SelectPermutationOfHits(int i, int mul, int l, int *r, QwHit *hx[DLAYERS][MAXHITPERLINE], QwHit **ha)
void AddHit(const QwHit *hit)
Add a single hit.
Definition: QwTreeLine.cc:219
An options class which parses command line, config file and environment.
int selectx(double *xresult, double dist_cut, QwHit **hitarray, QwHit **ha)
Definition of the track search tree.
double GetElementAngleCos() const
int fR3FirstWire
Definition: QwTreeLine.h:229
bool IsValid() const
Is this tree line valid?
Definition: QwTreeLine.h:90
QwTreeLine * next
Definition: QwTreeLine.h:231
Double_t fOffsetY
y coordinate (at MAGNET_CENTER)
void r3_TreelineFit(double &slope, double &offset, double cov[3], double &chi, const std::vector< QwHit * > hits, double z1, int wire_offset)
Double_t fSignedResidual[12]
double GetDetectorRollSin() const
QwHit * fHits[2 *MAX_LAYERS]
Definition: QwTreeLine.h:224
Hit structure uniquely defining each hit.
Definition: QwHit.h:43
void SetUsed(const bool isused=true)
Definition: QwTreeLine.h:97
#define MAX_LAYERS
Definition: globals.h:8
double GetZPosition() const
double GetElementAngle() const
#define QwWarning
Predefined log drain for warnings.
Definition: QwLog.h:45
int contains(double var, QwHit **arr, int len)
double GetXPosition() const
void GetSubList_Plane(EQwRegionID region, EQwDetectorPackage package, Int_t plane, std::vector< QwHit > &sublist)
bool IsValid() const
Int_t fNumMiss
missing hits
double fXY[2][2]
which satisifies
Definition: uv2xy.h:148
Contains the straight part of a track in one region only.
QwPartialTrack * TcTreeLineCombine(QwTreeLine *wu, QwTreeLine *wv, QwTreeLine *wx, int tlayer, bool drop_worst_hit)
The.
EQwDirectionID GetDirection() const
Get the direction.
double CalculateAverageResidual()
Calculate the average residuals.
Definition: QwTreeLine.cc:296
Int_t fNumHits
used hits
MyFCN(std::vector< QwHit * > fhits)
#define QwError
Predefined log drain for errors.
Definition: QwLog.h:40
int GetOctant() const